home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-02-08 | 165.7 KB | 3,154 lines |
- 5.1 Bibliothek: Allgemeines 5 - 1
- ________________________________________________________
-
-
- 5.1 Allgemeines zur Bibliothek
-
-
- Funktionsübersicht
-
- Bevor Sie weiterblättern und womöglich von der Funktionsvielfalt der über
- einhundert Module erschlagen werden, geben wir Ihnen eine kleine Übersicht.
-
- Einige Module kennen Sie sicher schon aus Ihrem Modula-2 Buch:
-
- - InOut zur Ein-/Ausgabe über Tastatur und Bildschirm,
- - Terminal ebenso (aber nur auf TOS-Bildschirm ohne GEM!)
- - Mathlib0 mit mathematischen Funktionen für REALs/LONGREALs,
- - Strings zum Arbeiten mit Zeichenketten und
- - Storage um NEW und DISPOSE verwenden zu können.
-
- Wenn Sie Neueinsteiger in Modula-2 sind, reicht es aus, wenn Sie sich erst
- einmal nur mit diesen Modulen beschäftigen.
-
- Für Fortgeschrittene folgt eine Übersicht weiterer nützlicher Module:
-
- Dateifunktionen:
- Files, Text, NumberIO, Binary, Directory.
-
- Grafik (GEM)
- AES..., VDI..., GEM..., ObjHandler, EventHandler, TextWindows,
- WindowBase, WindowLists, EasyGEM0, EasyGEM1.
-
- String/Zahlen-Umwandlung:
- Convert, StrConv, Strings, FuncStrings.
-
- Tastatur- und Zeichenauswertung:
- Characters, Keyboard.
-
- Programmkontrolle:
- Loader, ModCtrl, PrgCtrl.
-
- Diverse Hilfsfunktionen
- SysUtil0 - Variablenvergleiche, -löschen, -lopieren, Bit-Funktionen
- SysUtil1 - Speicherzugriffe aller Art, auch im Supervisormodus
- SysUtil2 - SetJump/LongJump (wie in C), Supervisormodus
- Clock - Datums-/Zeitbestimmung
- TimeConvert - Datums-/Zeit-Ein- und Ausgabe
- Lists - Verwaltung allgemeiner Listen
- RandomGen - Zufallszahlenerzeugung
-
- Alle Module sind jeweils in ihren Definitionstexten (s. Anhang) dokumentiert!
- 5.1 Bibliothek: Allgemeines 5 - 2
- ________________________________________________________
-
-
- Übersicht der vorhandenen Module
-
- Folgende Megamax-Module stehen Ihnen incl. Quelltexten zur Verfügung
- (Ordner MOS):
-
- GEMDebug - Hilfsmodul zum schrittweisen Ausführen v. Modula-Programmen
- TOSDebug - wie GEMDebug, aber mit TOS- statt Fensterausgabe
-
- GEMError - Treibermodul zum Abfangen v. Laufzeitfehlern (komfortabel)
- SimpleError - Wie GEMError, nur einfacher (siehe Kapitel 2.6 über Linker)
- GEMScan - Hilfsmodul zum Anzeigen v. Laufzeitfehlern
-
- GEMIO - Treibermodul zur Ausgabe von InOut in ein GEM-Window
- TOSIO - Treibermodul zur Ausgabe von InOut über BIOS-Routinen
- GEMDOSIO - Treibermodul zur Ausgabe von InOut über GEMDOS-Routinen
-
- M2Init - Initialisierungsmodul für alle gelinkten Programme
- MM2Shell - Die Shell zum Selbstverändern
- MOSConfig - Konfiguationsvariablen für Loader, ErrBase, InOut usw.
-
- Von folgenden Modulen haben Sie die Codeversionen erhalten (Ordner IMP):
-
- ArgCV - Auswertung der Argumentzeile (Command-Line)
- ArgCVIO - Auswertung der Argumentzeile mit E/A-Umleitungsmöglichkeit
- Binary - Dateisystem: E/A für Binärdaten, Seek, FileSize
- BinOps - Vergleichsfunktionen für jeweils zwei Werte
- BIOS - BIOS-Funktionen
- Block - Sehr schnelles Löschen und Kopieren großer Datenbereiche
- Calls - Aufruf von Modula-fremden Routinen (z.B. Betriebssystem)
- Characters - ASCII-Konstanten und Funktionen zum Auswerten von Zeichen
- Clock - Zeit- und Datumsbestimmung
- Compressions- Datenkomprimierung
- Console - Wie Terminal, jedoch Ausgabe über GEMDOS statt BIOS
- Convert - Umwandlung Zahlen <-> Strings (siehe auch StrConv)
- Directory - Löschen u. Umbenennen v. Dateien, Directory-Hilfsfunktionen
- EasyExceptions - Komfortables Abfangen von Laufzeitfehlern
- ErrBase - Grundmodul zum Abfangen von allgemeinen Laufzeitfehlern
- Excepts - Abfangen der Exceptions des Prozessors (680x0)
- FastStrings - Alternatives Strings-Modul
- FileBase - Dateisystem: Fehlerbehandlung und Device-Treiber
- FileNames - Zusammensetzen und Analysieren von Datei- und Pfadnamen
- Files - Dateisystem: Öffnen und Schließen v. Dateien
- FPUSupport - Für Benutzung der FPU in Accessories und Coroutinen
- FuncStrings - Komfortablere String-Funktionen (Pascal-ähnlich)
- GEMDOS - GEMDOS-Funktionen
- HdlError - Spezielles Modul zum Abfangen von allg. Laufzeitfehlern
- InOut - Standard Ein- und Ausgabe
- InOutBase - Modul für InOut-Treiber (z.B. GEMIO, TOSIO, GEMDOSIO)
- 5.1 Bibliothek: Allgemeines 5 - 3
- ________________________________________________________
-
-
- KbdCtrl - Direkte Tastaturabfrage/-kontrolle
- Keyboard - Auswertung von Tasten mit sog. Scan-Codes
- LibFiles - Verwaltung von Library-Dateien
- Lists - Verwaltung doppelt verketteter Listen
- Loader - Ausführen von Programmen, auch mit Load-Time-Linking
- MathLib0 - Mathematische Grundfunktionen f. REAL-Zahlen
- ModCtrl - Modulverwaltung, Prozeduren als Prozeß starten
- MOSGlobals - System-globale Konstanten und TYPE-Definitionen
- NumberIO - Dateisystem: E/A von Zahlen in Textform
- Paths - Dateien-Suchfunktionen
- PathEnv - Directory-Umgebung: HomePath und File-Selector
- PathCtrl - Verwaltung von Pfadliste f. Paths-Modul
- PrgCtrl - Programm-/Prozeßkontrolle (siehe auch ResCtrl)
- RandomGen - Zufallszahlenbestimmung
- ResCtrl - Modulkontrolle (siehe auch PrgCtrl)
- ResourceHandler - komfortable Prozeßkontrolle (setzt auf PrgCtrl, ResCtrl auf)
- Runtime - Laufzeitfunktionen, automatisch vom Compiler importiert
- Storage - Speicherverwaltung
- StorBase - Systemnahes Modul zur Speicherverwaltung
- StrConv - Erweiterte Zahlenumwandlungsfunktionen zu Convert
- StringEditor - Allg. Funktion zur komfortablen Eingabe einer Textzeile.
- Strings - String-Funktionen (siehe auch FastStrings, FuncStrings)
- SysCtrl - Hilfsroutinen für den Scanner (Module GEMError, GEMScan)
- SysInfo - Ermittelt Prozessortype, Koprozessor, TOS-Version
- SysTypes - Definition v. Systemtypen
- SysUtil0 - Hilfsfunktionen zum Löschen v. Variablen, Vergleichen usw.
- SysUtil1 - Speicherzugriffe aller Art, auch im Supervisormodus
- SysUtil2 - SetJump/LongJump (wie in C), Super-Funktion
- SysVars - Systemvariablen des TOS
- TermBase - Treibermodul zu Terminal
- Terminal - InOut-Treiber f. TOS-Bildschirm (BIOS-Ein-/Ausgaben)
- Text - Dateisystem: E/A von Textdaten
- < >
- TimeConvert - Umwandlung Zeit/Datum - Text (s. Clock)
- UserBreak - Ermöglicht Abbrechen von Programmen über Tastatur
- UserTrace - Alternative zu Debug
- VT52 - Escape-Sequenzen des VT-52-Emulators (f. Textausgaben)
- XBIOS - XBIOS-Funktionen
- XBRA - Bequeme XBRA-Installation
- 5.1 Bibliothek: Allgemeines 5 - 4
- ________________________________________________________
-
-
- AES... - AES-Funktionen des GEM
- VDI... - VDI-Funktionen des GEM
- EasyGEM0 - Allgemeine GEM-Hilfsfunktionen
- EasyGEM1 - Bequemer Aufruf des Datei-Selektors und der Clipboard-Funk~
- tionen (Klemmbrett, Scrap-Directory)
- EventHandler - Zentrale Verwaltung aller Events des GEM für das MOS
- FastGEM0 - Teils optimierte VDI-Funktionen
- FileManagement - Shell-Funktionen: Kopieren, Löschen usw.
- GEMEnv - Verwaltung der GEM-Umgebung
- GEMGlobals - Definitionen globaler GEM-Strukturen
- GrafBase - Grafische Hilfsfunktionen
- KbdEvent - Synchronisiert Tastenereignisse mit Sondertasten (Shift usw.)
- LineA - Line A-Funktionen des TOS.
- ObjHandler - Komfortabler Zugriff auf GEM-Objektbäume
- TextWindows - Komfortable Fensterverwaltung für Textausgaben
- WindowBase - Allgemeines Fenster-Kontrollmodul
- WindowLists - Verwaltet automatisch Textzeilen in einem Fenster
-
- Die folgenden Module sind nicht dokumentiert, da sie nur systemintern
- verwendet werden und Änderungen vorbehalten sind:
-
- GEMShare - GEM-Systemmodul
- InOutFile - Hilfsmodul für InOut
- MOSCtrl - Grundmodul für alle Programme
- ModBase - Hilfsmodul für Loader & ModBase
- SFP004 - Verwaltung f. evtl. vorhandenen Mathe-Koprozessor (68881)
- SystemError - Programmabbruch bei fatalen Fehlern (Speichermangel usw)
-
- Module, die nicht zum MOS gehören und jederzeit von uns oder Ihnen geändert
- werden können:
-
- MM2ShellRsc - GEM-Resource-Konstanten, mit NRSC ASH.PRG zu erzeugen.
- _
- Wollen Sie die Shell erweitern, dürfen Sie natürlich dabei auch
- eine neue Resource-Datei erzeugen und verwenden, denn sie
- wird nur von der Shell importiert, auf deren Quelltext Sie
- ebenfalls Zugriff haben.
- ShellMsg - Hilfsmodul zur Kommunikation zw. Shell, Compiler und Linker.
- Achtung - greifen Sie nicht in Ihren normalen Anwendungen
- darauf zu! Erstens sind die Werte in gelinkten Programme
- nicht mehr initialisiert (weil das nur die Modula-Shell tut),
- zweitens behalten wir uns jederzeit Änderungen daran vor,
- so daß Sie dann Versionskonflikte oder andere Probleme
- bekommen.
- 5.1 Bibliothek: Allgemeines 5 - 5
- ________________________________________________________
-
-
- Beispielprogramme (im DEMO-Ordner - Dokumentation in den Quelltexten)
-
- AccDemo - einfache Accessory-Demo
- AsmDemo - Beispiele für Aufruf der TOS-Funktionen in Assembler
- Dhrystone - Verbreitetes Testprogramm für Compiler-Qualität (Codeerz.)
- ExcDemo - Demonstriert Anwendung des Moduls Excepts
- ExcTest - Demonstriert Anwendung des Moduls Exceptions
- Hatschi - Demonstration von Coroutinen, auch als Interrupts
- InitPath - Hilfsmodul zum Initialisieren einer Pfadliste f. Paths-Funktionen
- KbdTest - Residentes Programm f. Tastaturmakros (KbdCtrl, ModCtrl)
- LocalModules - Zeigt die möglichen Import-/Export-Verhältnisse
- Sieve - Auch ein Testprogramm für Compiler-Qualität (Codeerzeugung)
- TextDemo - Demoprogramm für die VDI-Textausgabe
- Tiefe - Sind/waren Sie auch ein MAD-Fan?
- WdwLists - Zeigt Anwendung von WindowLists
-
-
- Hilfsprogramme (im UTILITY-Ordner - Dokumentation in den Quelltexten)
-
- CompInit - Ermöglicht es, den Compiler als gelinktes Programm zu starten,
- z.B. vom GEM-Desktop aus, um mehr Speicher frei zu haben.
- CmpFiles - Kann mehrere Dateien in zwei Verzeichnissen vergleichen
- Decode - Dekodiert Dateien
- DelFiles - Löscht mehrere Dateien auf einmal
- DoSysInfo - Zeigt Systeminformationen an (TOS-Version, Scrap-Dir usw.)
- Encode - Kodiert (komprimiert) Dateien
- ExecMod - Damit kann jedes noch ungelinkte Programmodul auch vom
- Desktop gestartet werden
- GPA - Ermittelt die Adresse von Prozeduren der Module im Speicher
- LibManager - Anlegen und Bearbeiten von Library-Dateien
- LinkInit - Ermöglicht es, den Linker als gelinktes Programm zu starten,
- z.B. vom GEM-Desktop aus, um mehr Speicher frei zu haben
- ModLoad - Ein nettes Programm, das die Mächtigkeit von Megamax
- Modula (speziell des Loaders) mal so richtig ausnutzt
- ModList - Ähnlich Alternate-R in der Shell, aber ausführlicher
- ModTrace - Residentes Programm. Zeigt alle Module an, die durch
- Loadtime-Linking in der Shell geladen werden
- Monitor - Erlaubt den Aufruf des Templemon beim Programmstart.
- PathEdit - Prüfen und Ändern der Pfadlisten in der Shell
- SetTime - Sorgt immer für korrekt eingestellte Zeit/Datum. Unbedingt
- übersetzen, linken und in den AUTO-Ordner kopieren (s. auch
- Kapitel 2.7), wenn keine Uhr im Rechner vorhanden ist!
- ShowKeys - "Quick-And-Dirty"-Programm, das alle Tasteninformationen
- anzeigt (auch Scan-Codes), benutzt Keyboard & KbdCtrl.
- Time - Anzeigen und Einstellen von Datum und Zeit
- Timer - komplexere Accessory-Demo
- 5.1 Bibliothek: Allgemeines 5 - 6
- ________________________________________________________
-
-
- Allgemeine Hinweise zu den Modulen
-
- Die Systemmodule, Programmkontrollmodule, Dateimodule sowie einige weitere
- Module bilden zusammen das "Modula Operating System", kurz MOS genannt.
-
- Sys-Funktionen
-
- In einigen Modulen finden sich Prozeduren, deren Namen mit Sys beginnen. Sie
- ergänzen immer ähnliche Prozeduren ohne diesen Prefix. Beispiel: SysOpen
- neben Open und SysAlloc neben ALLOCATE. Wo immer dies auftritt, erzeugen
- die Prozeduren Resourcen (z.B. Dateien, Speicherbereiche), die normalerweise
- spätestens bei Beendigung des Programms (Prozeß) wieder freigegeben werden
- sollen. Damit nichts verloren geht, wenn ein Programm nicht selbst dafür
- sorgt, bei Programmende alles wieder freizugeben bzw. zu schließen, wird dies
- automatisch von den Modulen des MOS durchgeführt. Nun gibt es Fälle, wo
- dies nicht erwünscht ist. Z.B. ist es möglich, über globale Variablen eines
- anderen Programms (Prozeß) Speicher anzufordern, der beim Enden des
- Programms, das den Speicher anforderte, nicht automatisch freigegeben
- werden soll. In diesem Fall wäre der Speicher mit SysAlloc statt ALLOCATE
- anzufordern. Die Sys... Funktionen sorgen also allgemein dafür, daß die damit
- angelegten Resourcen nicht bei Programmende automatisch freigegeben
- werden. Sie können dann nur durch den expliziten Aufruf der jeweils
- zugehörigen Freigabeprozedur freigegeben werden (z.B. Close, DEALLOCATE).
-
- Wichtig ist die Anwendung solcher Sys-Funktionen vor allem bei Programmen,
- die resident bleiben (z.B. mit Hilfe der Funktion InstallModule aus ModCtrl) und
- bei Accessories. Bei Accessories sollten immer, wenn möglich, Sys-Funktionen
- verwendet werden, da es sonst aufgrund eines Konzeptionsfehlers vom TOS
- z.B. passieren kann, daß ein im ACC angeforderter Speicherbereich bei
- Beendigung eines vom Desktop gestarteten Programms wieder freigegeben
- wird, was dann zum Totalabsturz des Rechners führen kann.
-
- Systemfunktionen
-
- Es sind einige Funktionen in den Quelltexten als systemzugehörig oder intern
- ausgewiesen. Solche Funktionen dürfen in keinem Fall von Ihnen ohne
- ausdrücklichen Hinweis von unserer Seite verwendet werden. Auch wenn Sie
- glauben, zu wissen, was die Funktionen im einzelnen tun - wir müssen Sie
- warnen, wir haben da schon böse Überraschungen erlebt! Teilweise behalten
- wir uns auch vor, diese Funktionen in späteren Versionen intern für andere
- Zwecke zu mißbrauchen.
- 5.1 Bibliothek: Allgemeines 5 - 7
- ________________________________________________________
-
-
- Übertragung (Portierung) von Modula-2 Programmen fremder Systeme
-
- Wenn Sie Programme von anderen Modula-2 Systemen übernehmen wollen,
- können Programmänderungen notwendig werden. Zum einen ist es möglich, daß
- hardwarespezifische Zugriffe stattfinden. Hier mag eine Anpassung schwierig
- sein, und wir können Ihnen dabei leider nicht helfen. Dann kommt es vor, daß
- andere Modula-2 Compiler Datentypen in anderen Formaten verarbeiten und es
- dabei z.B. bei Typanpassungen zu verschiedenen Ergebnissen kommt. Das
- größte Problem liegt aber meistens in der Verwendung unterschiedlicher
- Library-Funktionen. Hierzu einige Hinweise:
-
- Strings
-
- Da Herr Wirth nicht das Format von Zeichenketten festlegte, sind mehrere
- Formate möglich. Häufig, wie auch bei Megamax Modula, beginnt das erste
- Zeichen eines Strings im ersten Element eines ARRAY 0..n OF CHAR. Die
- Zeichenkette, die in solch einem Feld steht, kann entweder das gesamte Feld
- ausfüllen oder durch ein Null-Zeichen (0C) begrenzt werden. Die Länge einer
- Zeichenkette ist also gleich der Position des ersten Null-Zeichens des Strings
- oder gleich der Feldelementanzahl. Es gibt Systeme, die den gesamten unbe~
- nutzten Rest des Strings mit Null-Zeichen füllen; bei Megamax Modula ge~
- schieht dies nicht - alle Zeichen nach einem Null-Zeichen in einem String
- werden ignoriert.
-
- Es ist theoretisch auch möglich, daß das erste Element eines Strings immer
- die Länge der gültigen folgenden Zeichen enthält. Dann beginnt das erste
- Zeichen einer Zeichenkette beim zweiten Feldelement, ein abschließendes
- Zeichen ist unnötig. Diesem Stringformat werden Sie wahrscheinlich nicht
- begegnen, höchstens, wenn Sie Pascal-Programme übernehmen. In diesem Fall
- müssen Sie beachten, daß sich bei indiziertem Zugriff auf Stringelemente die
- Positionen der Zeichen alle um Eins verschieben.
-
- Die Funktionen in einem Strings-Modul sind nicht normiert. Einige Standard~
- funktionen finden sich jedoch in jeder Modula-2 Implementation. Dazu zählen
- Pos, Assign, Delete, Insert, Concat (Concatenate) und Length. Letztere wird
- sicher nie Probleme bereiten, bei den anderen ergeben sich bis zu drei Unter~
- schiede zu anderen Systemen: die Reihenfolge von Parametern, die Anzahl
- derselben und das Verhalten bei Fehlern (Megamax Modula liefert einen BOOLEAN-
- Wert, der Fehler anzeigt, andere Systeme stoppen das Programm durch einen
- Laufzeitfehler). Das einfachste ist, sich ein Hilfsmodul zu erstellen, das die
- benötigten Funktionen mit den Parametern des fremden Systems exportiert und
- die Megamax-Strings-Funktionen darüber aufruft.
- 5.1 Bibliothek: Allgemeines 5 - 8
- ________________________________________________________
-
-
- Bildschirm E/A (Ein-/Ausgabe)
-
- Unsere WriteHex-Routinen geben das '$'-Zeichen selbst mit aus. Wenn Sie
- das stört, können Sie statt dessen die WriteNum-Routinen verwenden, die kein
- Zeichen voranstellen und auch mit Leerzeichen statt mit Nullen linksseits füllen
- können.
-
- Die Megamax-Module Terminal, TextWindows, Text und InOut geben Zeichen,
- die mit Read eingelesen wurden, nur wieder auf den Bildschirm aus, wenn sie
- keine Steuerzeichen, sondern sichtbare Zeichen sind. Dies hat sich in der
- Praxis bewährt. Programme für fremde Modula-2 Systeme könnten davon
- abhängig sein, daß jedes eingelesene Steuerzeichen auf den Bildschirm wieder
- ausgegeben wird, da dies ursprünglich so vorgeschlagen wurde. In diesem Fall
- behelfen Sie sich am besten ebenfalls mit einer Hilfsfunktion, die z. B. wie
- folgt aussieht:
-
- PROCEDURE Read ( VAR c: CHAR );
- BEGIN
- InOut.Read ( c );
- IF c <= 37C (* höchstwertiges Steuerzeichen *) THEN
- Write ( c ) (* Steuerzeichen ausgeben *)
- END
- END Read;
-
- Sie können aber auch das Modul Console verwenden - dies gibt jedes einge~
- gebene Zeichen gleich wieder aus, aber hat auch noch andere Eigenheiten, die
- Sie am besten im Definitionsmodul nachlesen.
-
- Ähnlich verhält es sich mit ReadString bei TextWindows, Console und Terminal.
- Bei Eingabeende mit der "Return"-Taste bleibt der Cursor hinter dem einge~
- gebenen Text stehen anstatt, in die folgende Zeile vorzurücken. Sollte dies
- stören, kann ähnlich wie beim obigen Beispiel eine Hilfsprozedur ReadString
- deklariert werden, die nach dem entsprechenden Aufruf in Terminal, Console
- bzw. TextWindows WriteLn nachfolgend aufruft.
-
- Umgekehrt gibt ReadString aus InOut am Ende immer CR/LF aus (springt also
- in die nächste Zeile). Ist dies unerwünscht, kann es generell durch Entfernen
- des WriteLn-Aufrufs in der entsprechenden Funktion in GEMIO, GEMDOSIO
- oder TOSIO verhindert werden (nach der Änderung muß das Treibermodul
- nicht nur neu übersetzt, sondern auch in die Shell neu eingelinkt werden, damit
- sich die Änderung bemerkbar macht).
- 5.1 Bibliothek: Allgemeines 5 - 9
- ________________________________________________________
-
-
- Auch verhalten sich die Readstring-Funktionen vieler Modula-Systeme beim
- Eingeben sehr unterschiedlich. Manche erlauben die Eingabe einer beliebigen
- Zeile bis zum Drücken von Return, andere beenden schon bei der Eingabe
- eines Leerzeichen oder lesen zwar auf einmal eine ganze Zeile ein, die
- folgenden ReadString-Aufrufe liefern aber immer nur Wort-Fragmente, die
- durch eingegebene Leerzeichen getrennt sind.
-
- Wir haben deshalb jeweils zwei Funktionen in Terminal und TextWindows dafür
- vorgesehen. Da diese Module als wählbare Ein-/Ausgabetreiber für InOut
- verwendbar sind und durch die Konfigurationsmodule GEMIO und TOSIO, die
- wir im Quelltext mitliefern, beliebig an InOut adaptierbar sind, brauchen sie
- selbst nur zwei Grundfunktionen zu bieten:
-
- * ReadFromLine liest eine Zeile mitsamt aller Control-Codes; bei Dateien wird
- gelesen, bis das Zeilenende erreicht oder der String gefüllt ist, bei
- interaktiver Eingabe kann so lange korrigiert werden, bis sie mit Return
- abgeschlossen wird. Es gibt hier auch noch die Funktion ReadString, die
- lediglich noch vorhanden ist, damit Megamax-Programme, die für die alte
- System-Version Eins, in der es noch kein ReadFromLine gab, ohne
- Änderungen weiterhin übersetzbar bleiben. ReadString sollte hier aber
- überhaupt nicht mehr verwendet werden, sondern, je nach Bedarf,
- ReadToken oder ReadFromLine (Normallfall).
-
- * ReadToken ermöglicht lediglich die Eingabe eines Wortes - sobald ein Leer-
- oder Control-Zeichen (also auch Return) eingegeben wird, kehrt ReadToken
- zurück.
-
- InOut greift nun über ein Treibermodul (z.B. GEMIO, TOSIO, GEMDOSIO) auf
- diese Funktionen zu. Dazu bietet es ebenfalls die Funktionen ReadFromLine,
- ReadToken und ReadString: Wie sich diese Funktionen verhalten, wird im
- Treibermodul bestimmt. So ist es möglich, ReadString entweder direkt auf
- ReadToken oder ReadFromLine abzubilden, oder mit Hilfe von ReadFromLine
- eine gepufferte Eingabe zu realisieren, die auch bei Read-Aufrufen aus der
- gepufferten Zeile liest. Das soll Sie aber nicht verwirren, deshalb sparen wir
- uns nun weitere Erklärungen - verstehen Sie es einfach so: Benutzen Sie
- möglichst nur ReadFromLine/ReadToken (egal, ob aus Terminal, TextWindows
- oder InOut importiert) - wenn Sie einmal mit dem Übertragen eines Modula-
- Programms von oder zu einem anderen System konfrontiert werden, werden
- Sie diese Unterschiede erkennen und dann auch durchschauen, welche
- Änderungen Sie an den Treibermodulen vornehmen müssen.
-
- Wie schon erwähnt, sind also ggf. die Treiber GEMIO oder TOSIO für die
- Konfiguration der InOut-Funktionen verantwortlich: Die unterschiedlichen
- Konfigurationen müssen durch abgewandelte Versionen der Module GEMIO und
- TOSIO erstellt werden. So könnte man ein JPI IO erstellen, um die TopSpeed-
- _
- IO-Module nachzubilden, eine HM2 IO für Hänisch-Modula-Programme usw.
- _
- Solch ein Modul muß dann als erstes Modul im Hauptprogramm - also vor
- 5.1 Bibliothek: Allgemeines 5 - 10
- ________________________________________________________
-
-
- InOut - importiert werden. Dies wird übrigens auch empfohlen, wenn Sie bei
- normalen Megamax-Programmen, die InOut verwenden, die Ausgaben nicht in
- ein Fenster bekommen wollen: Schreiben Sie einfach
-
- IMPORT TOSIO; (*$E MOS *)
-
- vor den InOut-Import. Dann wird erstens das TOSIO-Modul, wie beim Linken,
- als InOut-Treiber verwendet, zweitens wird die Endung MOS erzeugt, was für
- einen TOS-Bildschirm (Textcursor, keine Maus) beim Starten sorgt.
-
- Bereits in Planung ist ein komfortableres Konzept für die nächste Shell-
- Version: Dann können Sie für jedes Modul individuell die Umgebung dauerhaft
- bestimmen, also seine Stack-Größe, die einzubindenden Treiber (sowohl für's
- Starten mit Load-Time-Linking als auch beim festen Linken) und andere
- nützliche Konfigurationen, die von außen bestimmbar sein sollten.
-
- Wenn Sie übrigens eigene Konfigurations- oder InOut-Treibermodule (z.B. für
- andere Modula-Systeme) erstellt haben, senden Sie sie doch im Rahmen des
- MEMOX-Service (s. Kapitel 1.5) an Application Systems! Damit helfen Sie nicht
- nur den anderen Megamax-Anwendern (auch uns, damit wir uns anderen
- Dingen widmen können, bei denen Sie uns nicht helfen könnten), sondern Sie
- erhalten dafür ja auch Beiträge anderer Anwender.
-
-
- Hinweise zu den Quelltexten
-
- Um Ihnen als Anwender die Möglichkeit zu geben, den Dialog mit dem Modula-
- System nach Ihren Wünschen optimal zu gestalten, haben wir die dafür
- zuständigen Module im Sourcetext mitgeliefert. Die interessantesten Module
- sind im folgenden aufgeführt, es lohnt sich aber auch, sich die anderen
- Sourcetexte (siehe UTILITY-, DEMO- und MOS-Ordner) einmal anzusehen.
-
-
- MM2SHELL.M
-
- Dies ist die Modula-2 Shell, das Desktop des Modula-Systems. Sie können
- sie beliebig verändern und erweitern. Außerdem lassen sich darin viele Bei~
- spiele für Programmieranwendungen finden, z. B. Zugriff auf GEM-Funktionen,
- Aufruf von Programmen oder Dateizugriffe. Dazu gehören auch die Dateien
- MM2SHELL.RSC und MM2SHELL.RSD, die mit Hilfe des Resource Construction
- Programms (RCP) verändert werden können. Beachten Sie, daß nach dem
- Ändern der Resource mit dem RCP beim neuen Abspeichern zwei Dateien
- MM2SHELL.D und MM2SHELL.I erzeugt werden, die die Konstanten der
- GEM-Objekte enthalten und von der Shell importiert werden. Allerdings müssen
- die Modulnamen in den beiden Quelltexten dazu erst von Mm2shell in
- Mm2shellRsc umbenannt werden!
- 5.1 Bibliothek: Allgemeines 5 - 11
- ________________________________________________________
-
-
- GEMError.I & SimpleError.I
-
- Diese Module werden bei Bedarf beim Linken von Programmen als Treiber mit
- eingebunden. Sie sorgen für das Abfangen und Anzeigen aller Laufzeitfehler.
- Zudem enthalten sie die Texte für Systemmeldungen, die nach Belieben in
- Englisch oder auch Esperanto übersetzt werden können.
-
-
- MOSConfig.I
-
- Hierin sind globale Variable enthalten, die von verschiedenen MOS-Modulen
- verwendet werden. Im Sourcetext können die Voreinstellungen nach Ihren
- Preferenzen verändert werden, z. B. Datumsformat (für Funktionen aus
- TimeConvert) oder Zahlendarstellungsformate (für REAL-Darstellungen).
-
-
- Bedienung der Ein-/Ausgabefunktionen
-
- Viele Funktionen der Megamax-Bibliothek bieten auch in der Benutzung über~
- durchschnittlichen Komfort, verglichen mit anderen Entwicklungssystemen auf
- Microcomputern.
-
- Besonders offensichtlich ist das beispielsweise bei Verwendung des InOut-
- Moduls durch das StdIO-Fenster, in dem die Ausgaben geschehen. Wartet das
- Programm auf eine Eingabe, macht es dauernd Ausgaben oder benutzt andere
- GEM-Funktionen, so daß die Event-Abfrage vom GEM regelmäßig aktiviert wird
- (beispielsweise ist dies auch durch regelmäßige Aufrufe der Prozedur
- FlushEvents aus dem Modul EventHandler zu erreichen). Das Fenster kann
- bewegt, in seiner Größe verändert und der Ausschnitt mit der Maus bestimmt
- werden.
-
- Weniger offensichtlich sind da schon die Editiermöglichkeiten bei Benutzung der
- Funktionen ReadString, ReadFromLine und ReadToken. Nicht nur, daß mit der
- Taste Backspace Korrekturen möglich sind, auch viele andere Tasten haben
- eine Funktion:
-
- Return Beendet Eingabe
- Enter Wie Return
- Undo Bricht Eingabe ab (liefert Leerstring)
- <
- - Cursor nach links
- >
- - Cursor nach rechts
- <
- Control - Zum Zeilenbeginn
- >
- Control - Zum Zeilenende
- Insert Ein Leerzeichen an Cursorposition einfügen
- Backspace Zeichen vor Cursor löschen
- Delete Zeichen unter Cursor löschen
- Esc Zeile löschen
- Clr (Shift-Home) Wie Esc
- Home Zeile ab Cursor löschen
- 5.1 Bibliothek: Allgemeines 5 - 12
- ________________________________________________________
-
-
- Ein weiteres Geheimnis, das nur diejenigen bisher erkannten, die die Doku~
- mentation zu den Funktionen in Convert aufmerksam gelesen haben, wollen wir
- nun lüften:
-
- Die Convert-Funktionen zum Umwandeln von Zeichenfolgen in Zahlen erlauben,
- daß die Werte mit einem "$"- oder "%"-Zeichen angeführt werden. Dies
- bewirkt dann eine Interpretation des Wertes als hexadezimale bzw. als binäre
- Zahl. Da alle Funktionen des Megamax-Systems, die Texte in irgendeiner
- Weise in Zahlen umwandeln, letztlich auf dieses Convert-Modul zurückgreifen
- (wozu haben wir uns schließlich für Modula-2 entschieden?!), können Sie also
- auch bei einem ReadCard-Aufruf statt "21" nun "$15" oder gar "%100000101"
- eingeben!
-
-
- Diverse Hinweise zu den Bibliotheken
-
- GEMDOSIO- und TOSIO-Ausgabe
-
- Geschehen die Ein-/Ausgaben über das Modul InOut, kann bekanntlich beim
- Linken durch die Linker-Optionen bestimmt werden, ob GEMDOSIO, TOSIO
- oder GEMIO verwendet werden soll. Bei Modulen, die mit Loadtime-Linking
- unter der Shell gestartet werden, ist diese Wahl nicht so einfach möglich.
- Normalerweise wird die Konfiguration verwendet, mit der die Shell gelinkt
- wurde: mit GEMIO. Der GEMDOS- oder TOSIO-Treiber kann dennoch
- verwendet werden: Schreiben Sie folgendes in eine Zeile vor dem InOut-Import
- im betreffenden Programm:
- IMPORT TOSIO; (*$E MOS *) (bzw. GEMDOSIO statt TOSIO)
- Damit wird beim Starten des Programms automatisch der TOS-Modus
- aktiviert. Zu beachten ist jedoch, daß beim Linken der Import aus dem
- Programm wieder entfernt werden muß, wenn dort ein anderes IO-Modul
- eingelinkt werden soll.
-
- Speicheranforderung mit ALLOCATE (Storage-Modul)
-
- Dem kommenden ISO-Standard für Modula nach wird ALLOCATE keinen
- Laufzeitfehler auslösen, wenn kein Speicher mehr verfügbar ist, sondern den
- Zeiger mit NIL beschreiben.
-
- Zweitens dürfen Sie nie davon ausgehen, daß der angeforderte Speicher
- gelöscht, d.h. mit Null-Bytes gefüllt, ist. Beachten Sie auch, daß die globalen
- Variablen bei Megamax Modula-2 zwar mit Null-Werten vorbesetzt werden,
- nach PIM und dem ISO-Standard dies aber nicht gefordert ist, Sie bei
- Portierung Ihrer Module demnach damit rechnen müssen, daß dies auf einem
- anderen Compiler/Rechner auch nicht der Fall ist.
- 5.1 Bibliothek: Allgemeines 5 - 13
- ________________________________________________________
-
-
- Verwendung von AES- und VDI-Funktionen (Maus-Funktionen und FormAlert)
-
- Sie sollten bei GEM-Programmen darauf achten, niemals auf VDI-Funktionen
- zurückzugreifen, wenn entsprechende Funktionen im AES vorhanden sind. Denn
- dort, wo das AES eigene Funktionen auf das VDI "aufsetzt", hat letztendlich
- auch das AES die Kontrolle, und Sie können unliebsame Seiteneffekte
- hervorrufen, wenn Sie das AES durch direktes Anwenden des VDI umgehen.
-
- Beliebtes Beispiel ist die Kontrolle der Maus: Es gibt die VDIInput-Prozeduren
- ShowMouse und HideMouse sowie GrafMouse in AESGraphics. Hier hat
- demnach das AES Vorrang. Wird ein Programm vom Desktop gestartet, wird
- die Maus über GrafMouse eingeschaltet. Wenn Sie nun in Ihrem Programm die
- Maus mit HideMouse abschalten, verschwindet sie zwar, das AES erfährt aber
- nichts davon, denkt also, sie sei noch sichtbar. Kommt nun eine AES-Funktion
- zum Zuge, die die Maus einschalten will, beispielsweise GrafMouse oder auch
- FormAlert (diese Funktion versucht selbstständig, die die Maus immer
- einzuschalten), geht das AES davon aus, die Maus sei sichtbar und teilt dem
- VDI deshalb auch nicht mit, die wirklich einzuschalten. Der Effekt: Die Maus
- ist nicht zu sehen. Fazit: Lassen Sie die Finger von Show- und HideMouse!
-
- Der richtige Gebrauch der UpdateWindow-Funktion...
-
- ... bei der Accessory-Initialisierung
-
- Bei der Programmierung eines jeden Accessories sollten Sie folgende Regel
- beachten: Zuerst der Aufruf von InitGem, danach RegisterAccessory und - dies
- ist besonders wichtig - UpdateWindow (TRUE). Erst dann dürfen eine
- GEM-Resource-Datei nachgeladen, Speicher angefordert und andere Betriebs~
- systemressourcen "geöffnet" werden. Am Ende der Initialisierung, also vor
- dem Event-Aufruf, muß dann noch der Aufruf von UpdateWindow (FALSE)
- nachgeholt werden! Siehe dazu beispielsweise das Demo-Programm Timer
- (UTILITY-Ordner).
-
- Wird das nicht beachtet, können u.U. schon während der Initialisierung
- Task-Wechsel zu anderen Accessories und insbesondere ein GEM-Programm
- per Autostart-Option gestartet werden und so dann die im Kapitel zu den
- Sys-Funktionen beschriebenen Fehler auftreten. (Ein ausführlicher Artikel dazu
- findet sich im ST-Magazin 11/90 auf Seite 68. Ein Dank an Laurenz Prüßner,
- der darin diese GEM-"Macke" aufgedeckt hat!)
-
- ... bei Timer-Events mit GEMDOS-Aufrufen
-
- Bekanntlich ist UpdateWindow dann zu benutzen, wenn Sie Manipulationen am
- Bildschirm vornehmen, also bei Benutzung bestimmter AES- und VDI-
- Funktionen. Ansonsten, z.B. bei GEMDOS- und BIOS-Funktionen, wird dies
- allgemein nicht für nötig gehalten. Das ist aber leider falsch! Wenn nämlich
- aus bestimmten Gründen dabei eine Alert-Box erscheint, können Accessories,
- 5.1 Bibliothek: Allgemeines 5 - 14
- ________________________________________________________
-
-
-
- die auf einen Timer-Event warten, zum Zuge kommen. Diese wiederum
- könnten einen GEMDOS-Aufruf tätigen. Wenn aber gerade die Haupt~
- anwendung selbst einen GEMDOS-Aufruf vornahm, ergibt das einen unerlaubten
- Wiedereintritt ins GEMDOS, die Folge ist ein Absturz des Rechners.
-
- Wie kann es dazu kommen? Die besagte Alert-Box erscheint, wenn eine
- Funktion aufgerufen wird, die den Critical Error Handler aufruft, weil
- beispielsweise keine Disk im Laufwerk steckt oder weil sie nicht gelesen/
- beschrieben werden kann. Die FormAlert-Routine des GEM verhindert in diesen
- Fällen aber nicht, daß Timer-Events ausgewertet werden und so kann ein
- Accessory zum Zuge kommen. Der eigentliche Fehler passiert aber erst dann,
- wenn das Accessory einen Wiedereintritt ins GEMDOS vornimmt. Dies ist
- praktisch immer der Fall, wenn der Critical Error Handler aktiviert wurde, weil
- dann ja meist gerade ein Diskzugriff über die GEMDOS-Funktionen erfolgt.
-
- Was ist also zu tun? Wenn Sie Timer-Events behandeln, müssen Sie
- währenddessen auch alle evtl. vorkommenden GEMDOS-Aufrufe durch
- UpdateWindow einklammern! Da Sie bei Verwendung der Modula-Bibliotheks~
- funktionen sich dessen u.U. nicht sicher sein können, klammern Sie am besten
- die ganze Timer-Event-Behandlung entsprechend ein.
-
- Sie können den Fehler übrigens leicht probeweise hervorrufen: Nehmen Sie das
- Timer-Accessory (UTILITY-Ornder) und entfernen Sie aus der Event-Schleife,
- in der die Zeit neu ausgegeben wird, die UpdateWindow-Aufrufe. Installieren
- Sie dann das Accessory, wie dort angegeben. Wenn Sie nun einen Diskfehler
- erzeugen, indem Sie z.B. Laufwerk A: ohne eine Disk darin öffnen, werden Sie
- eine Alert-Box erhalten und die Uhr wird währenddessen weiterlaufen. Bei
- Bestätigung der Alert-Box erhalten Sie dann einen Systemabsturz (das
- Timer-Modul ruft über das Clock-Modul indirekt eine GEMDOS-Funktion auf,
- die die aktuelle Zeit ermittelt).
-
- Die FPU und Accessories
-
- Die Entwickler von Atari empfehlen, die FPU in Accessories nicht zu benutzen.
- Der Grund dafür liegt darin, daß im TOS keine Funktionen vorgesehen sind, die
- das Benutzen der FPU von mehreren GEM-Tasks (Hauptprogramm und
- Accessories) regelt. Wenn beispielsweise die Register der FPUmit Werten
- belegt sind, und dann ein anderes Accessory zum Zuge käme und auch die
- FPU benutzt, würde sie wahrscheinlich die Register-Werte überschreiben. So
- denkt Atari.
-
- Wir haben zur Lösung das Modul FPUSupport geschaffen. Das bietet
- Funktionen zum Retten und Restaurieren des gesamten FPU-Status incl.
- Register und sonstiger Einstellungen (z.B. Rundungsmodus). Wollen Sie also in
- einem Accessory die FPU benutzen, sehen Sie sich dieses Modul an. Dort
- finden Sie die weiteren Hinweise.
- 5.2 Bibliothek: Programme, Module und Prozesse 5 - 15
- ________________________________________________________
-
-
- 5.2 Programme, Module und Prozesse
-
-
- Das Modulkonzept
-
- Als Programme werden im Folgenden alle die Dateien bezeichnet, die z.B. vom
- Desktop aus direkt ausgeführt werden können. Als Module werden die vom
- Modula-2 Compiler erzeugten Code-Dateien bezeichnet.
-
- Auch Compiler für andere Sprachen erzeugen in der Regel nicht sofort aus~
- führbare Dateien. Statt dessen müssen diese Dateien mit weiteren, schon
- compilierten Dateien (die die "importierten" Funktionen und Variablen enthal~
- ten), zusammengelinkt (gebunden) werden. Das TOS (Betriebssystem des
- Atari) bietet nun eine Funktion, mit der solche Programme geladen und
- gestartet werden können. Diese wird z.B. aktiviert, wenn man eine Programm~
- datei auf dem Desktop doppelt anklickt. Aber auch ein gestartetes Programm
- kann wiederum ein weiteres aufrufen.
-
- Im MOS (Modula-2 Betriebssystem) gibt es eine Funktion, die in der gleichen
- Weise Module zum Ausführen laden kann. Das Dazuladen und Linken der
- importierten Module wird dabei automatisch erledigt. Dabei werden nur die
- importierten Module nachgeladen, die sich noch nicht im Speicher befinden.
- Schon vorhandene Module werden ganz einfach von den neuen Modulen
- mitbenutzt.
-
- Damit man die Ladefunktion des MOS überhaupt benutzen kann, muß erst
- einmal ein Programm gestartet werden, das diese Funktion enthält. Die
- Funktion kann sich nur in einem Programm der herkömmlich gelinkten Art
- befinden, und das Programm muß über die TOS-Ausführungsfunktion gestartet
- werden. Ein solches Programm besteht aus mehreren Modulen, die dann aber
- alle schon als vorhanden registriert werden, so daß, wenn dann ein anderes
- Modul gestartet werden soll, die im Programm vorhandenen Module mit~
- verwendet werden können (shared code).
-
- Praktisch sieht das also z.B. so aus: Man hat ein Hauptprogramm H1, das die
- Module U1, U2 und U3 importiert. Dieses Programm soll vom normalen Desktop
- aus gestartet werden können. Dazu wird es mit dem Linker gebunden.
-
- Wenn das gelinkte Programm dann durch Doppelklick gestartet wird, befinden
- sich die Module H1, U1 U2 und U3 im Speicher. Enthalte U1 nun die MOS-
- Funktion zum Starten weiterer Module. Dann kann z.B. in H1 programmiert
- worden sein, ein Modul H2 nachzustarten. H2 importiert außerdem U2 und U4.
- Wenn es nun über die MOS-Ausführungsfunktion gestartet wird, wird das
- Modul U4 nachgeladen. Die importierten Prozeduren aus U2 werden aus dem
- schon vorhandenen Modul mitverwendet, lediglich die Variablen werden bei U2
- ein weiteres Mal angelegt.
- 5.2 Bibliothek: Programme, Module und Prozesse 5 - 16
- ________________________________________________________
-
-
- Wenn man das gleiche unter TOS anstellen wollte, nämlich, daß ein Programm
- ein zweites nachstartet, müßten beide Programme mit jeweils allen benötigten
- Modulen gelinkt sein, was bedeuten würde, daß das erste Programm aus H1,
- U1, U2 und U3 bestünde und das Nachgeladene aus H2, U2 und U4. Somit
- würde ein Modul zwangsläufig doppelt im Speicher vorliegen, was unnötigen
- Speicherplatz verbräuchte.
-
- Das automatische Linken beim Ausführen macht sich besonders bei der
- mitgelieferten Modula-Shell positiv bemerkbar. Während die Shell durch viele
- importierte Module ziemlich viel Speicher belegt, belegen viele Modula-
- Programme, die von der Shell aus gestartet werden, kaum zusätzlichen
- Speicher, da meistens schon alle benötigten Module von der Shell zur
- Verfügung gestellt werden können.
-
- Ein weiterer Vorteil liegt darin, daß durch gemeinsame Benutzung von Variablen
- mehrere nacheinander gestarteten Module Daten übermitteln können. Z.B. wird
- das Modul ShellMsg von der Shell und dem Compiler importiert. Dadurch kann
- der Compiler, bevor er endet, in den dort deklarierten Variablen z.B. den
- Namen der erzeugten Codedatei oder bei einem Fehler den Fehlertext ablegen,
- und die Shell kann diese Daten dann weiterverwenden. Diese Option (shared
- data) muß allerdings erst über eine besondere Compiler-Direktive ($Y, s. Kap.
- 3.4) angewählt werden.
-
-
- Vom Modul zum gelinkten Programm
-
- Die gesamten MOS-Funktionen wurden so konzipiert, daß ein Programm erst
- als Modul unter der Modula-Shell getestet werden kann und am Ende, falls
- dies vonnöten ist, möglichst ohne Änderungen mit all seinen importierten
- Modulen zu einem Programm zusammengelinkt werden kann, das dann vom
- Desktop aus gestartet werden kann. In wenigen Fällen muß jedoch eine Anpas~
- sung des zu linkenden Programms durchgeführt werden.
-
- Wenn das von der Shell gestartete Modul mit SetChain einen Nachfolger
- bestimmt, kann dies nicht mehr geschehen, wenn das diese Funktion aufrufen~
- de Modul gelinkt ist und übers TOS gestartet wird. Denn das Nachladen des
- Folgeprogramms kann nur vom Aufrufer erledigt werden, und das TOS als
- Aufrufer läßt dies nicht zu. Solange das Modul von der Shell mittels der
- Loader-Funktion CallModule gestartet wird, kann diese Funktion nach Ende des
- ersten Moduls das nächste nachstarten. Wenn Sie nun also ein Programm
- geschrieben haben, das aus mehreren, sich abwechselnd nachladenden Modulen
- besteht, sollten die Module nie gelinkt werden. Statt dessen sollten Sie ein
- Hilfsmodul erstellen, das gelinkt wird und vom Desktop gestartet werden kann.
- Es importiert lediglich die Funktion CallModule und startet damit das erste
- Modul. Dieses Modul kann dann wiederum andere mittels SetChain nachstarten,
- da ja bei Modulende immer zum Hilfsprogramm zurückgekehrt wird.
- 5.2 Bibliothek: Programme, Module und Prozesse 5 - 17
- ________________________________________________________
-
-
- Allerdings kann auch die Funktion ShellWrite (Modul AESMisc) benutzt werden,
- um vom Desktop gestartete Programme - ähnlich SetChain - zu verketten.
-
- Ein Fehler, der häufiger vorkommt, entsteht nur bei optimiertem Linken:
- Während der Loader jedes importierte Modul vollständig einbindet und
- initialisiert, kann der optimierende Linker Module ganz entfernen, obwohl sie
- importiert werden. Dies passiert beispielsweise, wenn sie ein Modul
- importieren, ohne Prozeduren oder Variablen daraus zu benutzen. Initialisiert
- das Modul in seinem Körper Daten importierter Module, würden diese
- Anweisungen beim optimierten Linken verschwinden.
-
- Dieser Effekt kann leicht daran erkannt werden, daß beim Linken solch ein
- Modul erst im Fenster angezeigt, dann aber wieder gelöscht wird. In diesem
- Fall braucht das Modul lediglich mit der Direktive B+ übersetzt werden, am
- besten, indem gleich zu Beginn des Moduls (*$B+*) eingefügt wird.
-
- Zur Sicherheit kann auch erstmal das Programm nicht-optimiert gelinkt
- oder generell durch Eintragen von -B in der Compiler-Direktiven-Zeile der
- Shell jedes Ihrer Module entsprechend übersetzt werden.
-
- Wenn Sie diese Sonderfälle berücksichtigen, ist ein Modul, das unter der Shell
- lief, auch als "eigenständiges" Programm lauffähig. Es stellt sich jedoch die
- Frage, was passieren soll, wenn wider Erwarten doch noch Fehler im
- Programm auftreten. Unter der Shell werden automatisch Fehleranzeigen
- ausgelöst. Die Funktionen sind dazu von der Shell installiert worden. Auch
- solche Funktionen müssen beim Linken extra eingebunden werden. Es gibt hier
- einmal die Möglichkeit, das Modul GEMError einzubinden, das auch von der
- Shell zur Fehlerbehandlung importiert wird. Wem das zuviel ist, der kann die
- abgespeckte Version SimpleError verwenden oder einen der mitgelieferten
- Quelltexte modifizieren: Wenn die Variablen von FileBase unverändert bleiben,
- werden Dateien bei Programmende immer ohne Meldung automatisch
- geschlossen, Fehler immer ignoriert, und die Files-Funktion GetStateMsg liefert
- immer einfach eine Fehlernummer statt des passenden Textes. Also kann man,
- falls man sich seines Dateiumgangs sicher ist, die FileBase-Operationen aus
- dem eigenen GEMError entfernen.
-
- Bei den Laufzeitfehlern sollte man zumindest eine einfache Fehlermeldung
- weiterhin vornehmen, denn wenn die Fehler nicht abgefangen werden, gibt es
- höchstens diese häßlichen Bomben, und das Programm terminiert sofort, ohne
- daß man feststellen kann, was passiert ist.
-
- Über die Laufzeitfehlerbehandlung existiert ein ausführliches Kapitel zu den
- Modulen Excepts, ErrBase, HdlError und EasyExceptions.
- 5.2 Bibliothek: Programme, Module und Prozesse 5 - 18
- ________________________________________________________
-
-
- Ein Sonderfall ist die Verwendung des Moduls InOut. Unter der Shell werden
- Ausgaben über dieses Modul in einem Window dargestellt. InOut importiert
- selbst nicht das dafür verwendete Modul TextWindows, sondern InOutBase.
- Unter der Shell sind allerdings die TextWindows-Funktionen darauf zugewiesen.
- Wenn ein Programm, das InOut benutzt, gelinkt wird, muß ein Konfigurations~
- modul mit eingebunden werden, das diese Prozedurvariablen initialisiert. Dazu
- stehen wahlweise GEMIO, TOSIO oder GEMDOSIO zur Verfügung. GEMIO
- importiert TextWindows und weist dessen Funktionen auf die Prozedurvariablen
- in InOutBase zu, eben wie dies auch in der Shell geschieht. TOSIO dagegen
- verwendet statt dessen die Funktionen aus Terminal für InOut und GEMDOSIO
- verwendet das Console-Modul, sodaß auch Ein-Ausgabeumlenkung von außen
- möglich ist, beispielsweise durch die Benutzung von Command-Line-Shells. Das
- bewirkt, daß ein Programm, das TOSIO oder GEMDOSIO statt GEMIO
- eingebunden hat, die Ausgaben nicht auf ein Window tätigt, sondern den
- gesamten Bildschirm dafür verwendet. In diesem Fall sollten keine anderen
- GEM-Funktionen verwendet und das gelinkte Programm mit der Endung ".TOS"
- statt ".PRG" benannt werden.
-
- Sie können vor dem Linken eines Programm durch Aufruf der Linker-Optionen
- bestimmen, ob Sie GEMIO, GEMDOSIO oder TOSIO einbinden wollen. Ersteres
- ist in der Anwendung optisch sicher schöner, die anderen benötigen wegen
- sparsamerer Importe weniger Speicherplatz.
-
- Wenn Sie in dem zu linkenden Programm InOut nicht verwenden, brauchen Sie
- GEMIO, GEMDOSIO bzw. TOSIO auch nicht einzubinden. Wenn Sie vergessen,
- eines der Module einzubinden, obwohl InOut benutzt wird, erhalten Sie, wenn
- Sie das Programm dann starten, eine Fehlermeldung mit dem Text "InOut
- driver is missing!".
-
-
- Prozesse
-
- Wenn ein Programm unter TOS gestartet wird (also z.B. vom Desktop aus),
- richtet das TOS dafür einen Prozeß ein (Der Prozeßbegriff ist nicht mit den
- Modula-2 Coroutinen zu verwechseln!). In der Praxis bedeutet dies, daß sich
- das TOS merkt, daß ein neues Programm gestartet wurde und von nun an
- bestimmte Systemresourcen (z.B. Speicheranforderungen, Dateizugriffe)
- diesem Prozeß/Programm zugeordnet werden. Wenn das Programm/der
- Prozeß endet, können alle Systemresourcen des Programms erkannt und
- notfalls freigegeben werden (z.B. belegter Speicher wieder freigegeben, offene
- Dateien geschlossen).
-
- Gegenüber einem einfachen Unterprogramm hat ein Prozeß außerdem den
- Vorteil, daß er sich zu (fast) jeder Zeit und an jeder Programmstelle beenden
- kann und die Ausführung dann immer hinter der Programmstelle fortgeführt
- wird, die den Prozeß gestartet hat (wie bei einem Unterprogrammaufruf).
- 5.2 Bibliothek: Programme, Module und Prozesse 5 - 19
- ________________________________________________________
-
-
- Jeder Prozeß erhält eine Basepage. Dies ist ein Speicherbereich von 256
- Bytes, in denen bestimmte Daten angelegt werden, die der Prozeß ganz privat
- benötigt (ähnlich dem Workspace bei Modula-Coroutinen). Darin wird z.B. eine
- Textzeile abgelegt, die der Aufrufer übergeben hat (z.B. die Argumentzeile bei
- ".TTP"-Programmen) und die offenen Dateien registriert.
-
- Wenn ein Programm / Prozeß endet, kann es dem Aufrufer eine Nachricht in
- Form einer INTEGER-Zahl (-32768 bis 32767) liefern. Es ist sinnvoll, negative
- Werte zu liefern, wenn ein Fehler im aufgerufenen Programm auftrat, und Null,
- wenn nichts Besonderes zu melden ist.
-
- Im MOS (Modula Operating System) gibt es zwei Möglichkeiten, einen Prozeß
- zu starten. Entweder man startet ein Programm oder Modul mit der Funktion
- CallModule aus dem Modul Loader oder man startet ein Unterprogramm als
- Prozeß mit CallProcess aus ModCtrl. Solch ein Prozeß kann dann auf zwei
- Arten zu Ende geführt werden. Entweder läuft das Programm bzw. das
- Unterprogramm bis zum Ende durch oder es wird auf irgend eine Weise
- TermProcess aus PrgCtrl aufgerufen. Bei normaler Beendigung wird als
- Ergebnis des Prozesses eine Null über CallModule bzw. CallProcess geliefert,
- bei Aufruf von TermProcess kann ein selbst gewählter Ergebniswert (die
- INTEGER-Zahl) übergeben werden.
-
- TermProcess wird z.B. automatisch ausgeführt, wenn ein Programm durch
- einen Laufzeitfehler unterbricht und bei der dann angezeigten Fehlermeldung
- "Quit" oder "Abbruch" angewählt wird. Als Ergebniswert wird dann an den
- CallModule- bzw. CallProcess-Aufrufer die Laufzeitfehlernummer (s.
- MOSGlobals) geliefert.
-
- CallModule kann sowohl normale Programme als auch die vom Compiler
- erzeugten, ungelinkten Module starten. Wird ein Modula-2 Modul gestartet,
- werden alle importierten Module, die sich noch nicht im Speicher befinden,
- nachgeladen. Wenn der Prozeß endet, werden alle nicht mehr benötigten
- Module wieder freigegeben, d.h., daß der von ihnen belegte Speicherplatz
- wieder für neue Daten frei wird.
-
- Wenn man erreichen will, daß nicht bei jedem Programmaufruf mit CallModule
- das Programm bzw. die Module erneut geladen werden, kann man sie mit der
- Funktion LoadModule aus Loader einmal laden. Sie bleiben dann so lange im
- Speicher, bis UnLoadModule aufgerufen wird oder das Programm endet, das
- das Modul Loader importierte (z.B. die Shell).
-
- Ein gestartetes Modul kann mit SetChain aus Loader selbst bestimmen, daß
- nach dem eigenen Ablauf nicht zum Aufrufer zurückgekehrt sondern erstmal
- ein anderes Programm gestartet wird. Dies Nachstarten kann aber nur von
- ungelinkten Modulen aus geschehen - nach dem Ablauf eines eigenständigen
- Programms ist ja der Loader des MOS nicht mehr aktiv.
- 5.2 Bibliothek: Programme, Module und Prozesse 5 - 20
- ________________________________________________________
-
-
- Es gibt Anwendungen, bei denen es darauf ankommt, ein Programm nach~
- träglich und dauerhaft einzubinden. Dies kommt meist vor bei "Treibern" (z.B.
- RAMdisk-Programme) und Monitoren (Programme, die z.B. über andere
- Prozesse wachen). Solche Programme installieren Funktionen auf Vektoren
- bzw. Prozedurvariablen, die von dem Programm, in das sie sich einlinken,
- exportiert werden. Im MOS gibt es viele Möglichkeiten für solche Programme,
- z.B. können über die Treibervariablen in FileBase oder TermBase andere
- Ein-/Ausgabefunktionen eingebunden oder kurzzeitig Konfigurationen in
- MOSConfig geändert werden.
-
- Beispielsweise soll erreicht werden, daß alle Module, die der Loader lädt,
- angezeigt werden. Dazu exportiert das Modul Loader die Prozedurvariable
- Loading, die bei jedem Modulladen aufgerufen wird. Es gibt nun zwei
- Möglichkeiten. Entweder erweitert man die Shell um eine Funktion, die auf die
- Loader-Variable zugewiesen wird und die Ausgabe der geladenen Module
- durchführt. Will man aber sich die Änderung in der Shell ersparen, muß man
- ein kleines Programm erstellen, das dies übernimmt. Die Ausgabefunktion darf
- aber nur so lange auf Loading zugewiesen sein, wie das Modul im Speicher
- steht. Will man zurück in die Shell, um Module zu starten, damit die Funktion
- sie anzeigen kann, endet aber das Programm und wird wieder aus dem
- Speicher entfernt.
-
- Die Lösung bietet die Funktion InstallModule aus ModCtrl. Sie bewirkt, daß das
- Modul, das die Funktion aufruft, mitsamt seiner importierten Module resident
- im Speicher bleibt, bis ModCtrl selbst aus dem Speicher verschwindet (also
- wenn z.B. die Shell abläuft).
-
- Wenn also das Modul vor dem Zuweisen der Loading-Variable erst
- InstallModule aufruft und dann der Prozeß beendet wird, bleibt die Ausgabe~
- prozedur weiterhin aufrufbar.
-
- Damit das Modul sich auch wieder freigeben und die Ausgabefunktion abmelden
- kann, gibt es die Möglichkeit, ein solches Modul erneut per CallModule zu
- starten. Das Modul kann dann mit FirstModuleStart (aus ModCtrl) erfragen, ob
- dies der erste Aufruf des Moduls ist, um so zu ermitteln, ob das Modul schon
- resident war. Ist dies der Fall, gibt es sich einfach wieder frei (mit
- ReleaseModule).
- 5.2 Bibliothek: Programme, Module und Prozesse 5 - 21
- ________________________________________________________
-
-
- Hier das vollständige Beispielprogramm:
-
- MODULE ShowMods;
-
- FROM SYSTEM IMPORT ADDRESS, ADR; IMPORT ModCtrl, Loader,
- AESForms, Strings, MOSGlob;
-
- VAR workSpace: MemArea; oldLoading: Loader.LoadingProc;
-
- PROCEDURE remove;
- BEGIN
- (* Wiederherstellen des alten Wertes: *)
- Loader.Loading:= oldLoading;
- END remove;
-
- PROCEDURE show ( modName, fileName: ARRAY OF CHAR;
- codeAddr: ADDRESS; codeLen: LONGCARD;
- varAddr: ADDRESS; varLen: LONGCARD );
- VAR s: Strings.String; ok: BOOLEAN; button: CARDINAL;
- BEGIN
- (* Hier wird jedes geladene Modul ausgegeben *)
- Strings.Concat (' 0 Lade ', fileName, s, ok);
- Strings.Append (s, ' OK ', ok);
- AESForms.FormAlert (1, s, button);
- (* GEM ist bereits durch die Shell initialisiert *)
- END show;
-
- BEGIN
- IF ModCtrl.FirstModuleStart () THEN
- (* Beim 1.Start wird die Ausgabefunktion eingerichtet. *)
- workSpace.bottom:= NIL; (* der normale Stack reicht aus*)
- ModCtrl.InstallModule (remove, workSpace);
- oldLoading:= Loader.Loading; (* Retten des alten Wertes *)
- Loader.Loading:= show (* Zuweisen der neuen Prozedur *)
- ELSE
- (* Beim wiederholten Start wird alles entfernt. *)
- remove; (* Wiederherstellen des alten 'Loading'-Wertes *)
- ModCtrl.ReleaseModule
- END
- END ShowMods.
-
-
- Im UTILITY-Ordner befindet sich ein entsprechendes Modul ModTrace.
- 5.2 Bibliothek: Programme, Module und Prozesse 5 - 22
- ________________________________________________________
-
-
- Modul- und Prozeßkontrolle
-
- Es gibt Anwendungen, die nicht einfach ohne weiteres beendet werden dürfen,
- sondern bei denen Einstellungen, die während eines Prozesses verändert
- wurden, wieder rückgängig gemacht werden müssen. Werden z.B. Interrupts
- verwendet, dürfen die Interruptvektoren nach Prozeßende nicht "in die Wüste"
- zeigen, weil sonst ein Systemabsturz möglich wäre. Da es möglich ist, daß ein
- Prozeß unbeabsichtigt, z.B. durch einen Fehler, beendet wird, kann mit der
- Funktion CatchProcessTerm aus PrgCtrl eine Prozedur installiert werden, die
- automatisch bei Beendigung des eigenen Prozesses aufgerufen wird.
- Genaugenommen wird die Prozedur dann ausgeführt, wenn der Prozeß endet,
- in dem der CatchProcessTerm-Aufruf erfolgte. Werden mehrere solcher
- Prozeduren während eines Prozesses angemeldet, werden sie beim Prozeßende
- in entgegengesetzter Anmeldungsreihenfolge aufgerufen (letztes zuerst).
-
- Module wie Files oder Storage sorgen automatisch dafür, daß offen gebliebene
- Dateien oder belegter Speicher freigegeben wird, wenn der Prozeß beendet
- wird, unter dem die Dateien geöffnet oder der Speicher angefordert wurde.
- Damit solche Funktionen über Beginn und Ende eines Prozesses Bescheid
- wissen, gibt es im Modul PrgCtrl die Funktion SetEnvelope zur Anmeldung einer
- Prozedur, die bei Prozeßbeginn und -ende aufgerufen wird.
-
- Im Files-Modul wird beispielsweise eine globale Variable, die das aktuelle
- Prozeßlevel bestimmt, verwaltet. Sie wird mit Hilfe der SetEnvelope-Funktion
- bei jedem Prozeßbeginn erhöht und bei jedem Prozeßende wieder verringert.
- Die Files.Open-Funktion merkt sich nun für jede geöffnete Datei den Wert des
- Prozeßlevels. Bei Prozeßende wird, bevor das Prozeßlevel heruntergesetzt wird,
- erst jede offene Datei geschlossen, die unter dem gerade zu beendenden
- Prozeßlevel eröffnet wurde.
-
- Werden Module erstellt, die Resourcen (z.B. Listen, Speicher, Dateien)
- verwalten können oder selber Resourcen anlegen oder globale Vektoren (z.B.
- Interrupts oder TRAPs) oder andere globale Einstellungen vornehmen, und
- sollen diese Module auch in Programmen verwendet werden können, die sich
- speicher-resident machen (mit InstallModule), darf zum automatischen
- Schließen bei Programmende nicht CatchProcessTerm, sondern CatchRemoval
- aus SysCtrl verwendet werden! Siehe dazu auch die Definitionstexte von
- PrgCtrl, SysCtrl, ResourceHandler sowie das Demo-Modul SysLibDemo im
- DEMO-Ordner.
- 5.2 Bibliothek: Programme, Module und Prozesse 5 - 23
- ________________________________________________________
-
-
- Programm- und Prozeßinformationen, Base Page und Argumentzeile
-
- Um zu erfahren, welche Module bei einem Programmstart geladen werden,
- wurde bereits die Verwendung der Funktion Loading weiter oben beschrieben.
- Um die Informationen über die augenblicklich geladenen Module zu erhalten,
- gibt es in ModCtrl die Funktion ModQuery. Ihr wird eine Prozedur übergeben,
- die wiederholt mit den Informationen über alle im Speicher befindlichen Module
- aufgerufen wird. Ein Beispielprogramm namens ModList befindet sich im
- DEMO-Ordner.
-
- Wenn man mit einem Debugger oder Maschinensprachemonitor von CallModule
- gestartete Prozesse tracen (schrittweise verfolgen) möchte, kann man die
- Loader-Variable Monitor auf eine Prozedur zuweisen, die das Monitorprogramm
- oder den Debugger aktiviert. Die Monitor-Prozedur wird immer direkt vor dem
- Aufruf des von CallModule zu startenden Moduls ausgeführt. Die Behandlung
- der Monitor-Variablen kann in derselben Weise wie bei dem Beispielprogramm
- für die Loading-Variable (s.o.) geschehen. Ein Beispielprogramm Monitor wird
- mitgeliefert (UTILITY-Ordner).
-
- Den Zeiger auf die Basepage jedes Prozesses erhält man mit der Funktion
- GetBasePageAddr aus PrgCtrl. Für den Normalanwender ist daraus nur die
- Argumentzeile interessant, die bei CallModule angegeben oder beim Start eines
- Programms von der Shell bestimmt werden kann. Für den Zugriff darauf bietet
- sich jedoch besser das Modul ArgCV an. Der Aufruf der dortigen Prozedur
- InitArgCV löst die Argumentzeile gleich in einzelne Argumente auf, und
- ArgCVIO erlaubt es zusätzlich, die Ein-/Ausgaben über InOut umzuleiten, falls
- das Programm als TTP-Anwendung vom Desktop gestartet werden soll: Um
- z.B. die Eingabe von der Datei "BATCH.TXT" zu ermöglichen, kann in der
- Argumentzeile "<BATCH.TXT" angegeben werden. Für Ausgabeumleitung kann
- ">" oder ">>" verwendet werden: ">" bestimmt eine neue Datei, während ">>"
- das Anfügen an eine bestehende Datei ermöglicht. Soll die Umlenkung auch
- schon vom aufrufenden Programm (z.B. Command-Shell) möglich sein, muß das
- Console-Modul, z.B. durch den InOut-Treiber GEMDOSIO, verwendet werden.
- Der Desktop (und z.Zt. auch die Megamax-Shell) prüfen die Argumentzeile
- nicht auf Umlenkungsanweisungen und deshalb ist es hier ggf. erforderlich,
- ArgCVIO zu verwenden.
-
- Mit Accessory aus PrgCtrl kann ermittelt werden, ob ein Programm als
- Accessory (mit Suffix ".ACC") gestartet wurde.
-
- Das Modul MOSCtrl ist für den Normalanwender tabu. Es stellt die grund~
- legenden Funktionen und Daten für die MOS-Prozeßkontrolle zur Verfügung
- und ist nur für die MOS-internen Module bestimmt.
- 5.2 Bibliothek: Programme, Module und Leerseiten 5 - 24
- ________________________________________________________
- 5.3 Bibliothek: Laufzeitfehler-Behandlung 5 - 25
- ________________________________________________________
-
-
- 5.3 Laufzeitfehler-Behandlung
-
-
- Was sind Laufzeitfehler ?
-
- Laufzeitfehler können unter mehreren Umständen eintreten. Z. B. kann eine
- Variable einen ungültigen Wert erhalten, eine Division durch Null erfolgen oder
- ein Pointerzugriff mit einem uninitialisierten Pointer durchgeführt werden.
-
- Nun ist es in den meisten Fällen zu aufwendig, solchen Fehlern programm~
- technisch zuvorzukommen. Man müßte z. B. vor jeder Berechnung mit Zahlen
- prüfen, ob die Ergebnisse nicht ungültig werden. Statt dessen können solche
- Prüfungen automatisch vom Mikroprozessor und vom Code, den der Compiler
- erzeugt, vorgenommen werden. Der Vorteil liegt darin, daß der Programmierer
- sich nicht selbst um die vielfältigen Prüfungen kümmern muß. Der Nachteil ist,
- daß die vom Prozessor oder vom Spezialcode des Compilers erkannten Fehler
- alle eine Standard-Fehlerbehandlung durchlaufen, anstatt individuell behandelt zu
- werden.
-
- Aus diesem Grund ist es nötig, sich beim Programmieren Gedanken darüber zu
- machen, ob absehbar mögliche Fehler vorher erkannt werden sollen, um darauf
- dann direkt zu reagieren, oder ob es ausreicht, nach einer Berechnung etc. zu
- erkennen, daß überhaupt ein Fehler aufgetreten war.
-
- Dazu ein Beipiel. Folgende Berechnung sei durchzuführen:
-
- lösung:= a * b + c DIV ( d * e );
-
- Wenn die Variablen a bis e alle möglichen Werte annehmen können, sind
- mehrere Fehler möglich:
-
- - Ein Überlauf tritt bei der Multiplikation von a * b auf.
- - Ein Überlauf tritt bei der Multiplikation von d * e auf.
- - Ein Überlauf tritt bei der Addition von d * e und c DIV d * e auf.
- - Eine Division durch Null tritt auf, weil d oder e Null ist.
-
- Wenn es darauf ankommt, herauszufinden, welche Variable einen illegalen Wert
- hat, muß dies in aufwendiger Weise vor der Berechnung geprüft werden. Ist
- dagegen nur wichtig, zu erfahren, ob überhaupt ein gültige Lösung dabei
- entsteht, reicht es aus, die automatische Fehlererkennung darüber wachen zu
- lassen.
-
- Die automatische Fehlererkennung liefert lediglich die Information, daß ein
- Fehler auftrat und was der Anlaß für den Fehler war. Für das Beispiel oben
- wird im Fehlerfalle nur übermittelt, daß entweder ein Überlauf oder eine
- Division durch Null den Fehler auslöste.
- 5.3 Bibliothek: Laufzeitfehler-Behandlung 5 - 26
- ________________________________________________________
-
-
- Fehlergruppen
-
- Laufzeitfehler kann man in vier Gruppen (Ursachen) aufteilen:
-
- - Exceptions: Dies sind Fehler, die der Mikroprozessor erkennt, z. B. 16
- Bit-Division durch Null oder Zugriff auf nicht vorhandenen Speicherbereich.
- Der Prozessor hat dafür an festen Systemadressen Sprungvektoren
- vorgesehen, die in einem solchen Fehlerfalle angesprungen werden. Es ist
- nicht möglich, die Erkennung der Fehler durch den Prozessor zu
- unterbinden.
-
- - Soft-Fehler: Dazu zählen alle Fehler, die durch extra programmierte
- Abfragen erkannt werden. Solche Abfragen werden z.B. vom Compiler
- erzeugt (wenn nicht die Option (*$R-*) eingestellt ist) und stehen auch in
- vielen der mitgelieferten Library-Module. Sie werden alle über eine
- erzwungene Exception-Auslösung gemeldet.
-
- - Raise-Funktionen: Damit können Sie selbst Fehlermeldungen auslösen. Dies
- ist z. B. sinnvoll, wenn Sie ein Modul mit mathematischen Funktionen
- programmieren. Dann können Sie selbst Fehlerabfragen durchführen und
- ggf. die Funktion RaiseError aus dem Modul ErrBase aufrufen, um einen
- normalen Laufzeitfehler zu simulieren.
-
- - Dateifehler: Das Dateisystem des MOS prüft in vielen Fällen nach, ob Sie
- einen vorher aufgetretenen Fehler, z. B. einen Lesefehler, erkannt haben.
- Ist dies nicht der Fall, wird eine Fehlermeldung ausgelöst.
-
- Die ersten drei Gruppen können, da sie alle gleichartige Fehler melden, von
- einer einzigen Funktion behandelt werden. Sie werden im Folgenden "allgemeine
- Laufzeitfehler" genannt. Die Dateifehler treten unter anderen Umständen auf
- und müssen auch anders behandelt werden.
-
- Darüber hinaus faßt das Modul EasyExceptions alle diese Fehler zusammen und
- ermöglicht auf eine höheren Ebene eine sehr komfortable Fehlerbehandlung.
- Dazu mehr am Ende dieses Kapitels.
- 5.3 Bibliothek: Laufzeitfehler-Behandlung 5 - 27
- ________________________________________________________
-
-
- Allgemeine Laufzeitfehler
-
- Die Fehler der ersten beiden Gruppen (s.o.) werden auf dem selben Weg
- gemeldet: über Exceptions. Mit dem Modul Excepts können diese und auch alle
- anderen Exceptions abgefangen werden. (Tritt eine Exception auf, die nicht
- abgefangen wird, blitzen nur kurz ein paar häßliche Bomben auf dem Atari-
- Bildschirm auf.) Das Modul bietet die Funktion InstallExc, mit der eine Prozedur
- angemeldet werden kann, die bei Eintritt einer der anzugebenden Exceptions
- aufgerufen wird. Wird bei einer Exception die Prozedur dann aufgerufen,
- bekommt sie Werte aller Prozessorregister vor der Exception übergeben. Sie
- kann dann entscheiden, ob sie selbst reagieren will. Wenn ja, kann sie z. B.
- eine Fehlermeldung anzeigen. Danach kann sie die Prozessorregister ändern
- und mit RETURN FALSE erreichen, daß die Prozessorregister zurückgeladen
- werden und das unterbrochene Programm fortgeführt wird. Wenn sie nicht
- reagieren will, kehrt sie mit RETURN TRUE zurück, und es wird vom Modul
- Excepts die Prozedur aufgerufen, die vor dem InstallExc-Aufruf für die
- Exception angemeldet war. Diese Prozedur kann dann genauso verfahren.
-
- Mit der Prozedur RaiseExc aus Excepts können Sie eine Exception an der
- Stelle simulieren, von der der Aufruf geschieht.
-
- Wird das Modul ErrBase eingebunden, ruft es automatisch InstallExc auf und
- fängt alle Exceptions, die von Modula-Programmen ausgelöst werden können,
- ab. Es exportiert eine Prozedurvariable, die bei einer solchen Exception oder
- bei Aufruf der dortigen Funktion RaiseError aufgerufen wird. Von Anwender~
- programmen sollte diese globale Variable aber in der Regel nicht verwendet
- werden, um Fehler abzufangen.
-
- Statt dessen gibt es noch ein weiteres Modul, HdlError, das eine interne
- Prozedur auf die Prozedurvariable aus ErrBase zuweist. Dieses Modul bietet
- nun die komfortablen Funktionen zum Abfangen und Behandeln der allgemeinen
- Laufzeitfehler.
-
- CatchErrors aus HdlError erlaubt es, Prozeduren anzumelden, die bei jedem
- allg. Laufzeitfehler aufgerufen werden. Die Prozedur bekommt bei einem
- Laufzeitfehler die Fehlernummer (alle Fehlernummern sind in MOSGlobals
- definiert und erklärt), einen optionalen Text, die Prozessordaten von der
- Exception, die Information, ob das Programm noch fortgeführt werden kann,
- und die Angabe, ob die fehlerauslösende Routine oder ihr Aufrufer als
- Verursacher gilt. Der Text kann v. A. bei RaiseError als zusätzliche
- Information neben der Fehlernummer übergeben werden. Bei vom Compiler
- erzeugten Fehlermeldungen oder bei Exceptions ist der Text immer leer. Wird
- die Prozedur aufgerufen, hat sie in der Regel drei Möglichkeiten:
- 5.3 Bibliothek: Laufzeitfehler-Behandlung 5 - 28
- ________________________________________________________
-
-
- - Sie will den Fehler nicht speziell behandeln. Dann verläßt sie die Funktion
- mit RETURN TRUE. Waren noch weitere, ältere CatchErrors-Aufrufe
- erfolgt, werden nun deren angemeldete Prozeduren in gleicher Weise
- aufgerufen. Ist keine weitere 'call'-Funktion vorhanden, wird das Programm
- mit der Fehlernummer als "Exitcode" (siehe PrgCtrl.TermProcess) beendet.
-
- - Sie hat den Fehler behandelt und möchte erreichen, daß das Programm
- hinter der Fehlerauslösung fortfahren kann. Dazu muß sie die Funktion mit
- FALSE verlassen. Dies sollte in der Regel nur getan werden, wenn es
- durch eines der Argumente, die der Prozedur übergeben wurden, erlaubt
- wird. Vorsicht: Bei Busfehlern und Adreßfehlern kann das Programm nicht
- ohne Änderung der Prozessorregister fortfahren !
-
- - Der Fehler wurde erkannt, und das Programm soll abgebrochen werden.
- Dann ist TermProcess aus PrgCtrl aufzurufen.
-
- Diese Wahlmöglichkeit hat nun riesige Vorteile. Stellen Sie sich vor, Sie haben
- eine Prozedur, die eine Berechnung durchführt. Sie soll ein Ergebnis liefern,
- das anzeigt, ob die Berechnung fehlerfrei verlief. Da nun damit gerechnet
- werden muß, daß darin ein Laufzeitfehler auftreten kann, wird vor der
- Berechnung mit CatchErrors eine Hilfsfunktion installiert. Tritt danach irgendein
- Fehler auf, wird die Funktion als erstes aufgerufen, und sie kann entscheiden,
- ob der Fehler in der Berechnung entstanden oder ein ganz anderer Fehler ist.
- Je nachdem setzt sie ein Fehlerflag und läßt die Berechnung zu Ende laufen,
- oder sie läßt den außerordentlichen Fehler von der zuvor installierten Fehler~
- behandlung bearbeiten (dies führt dann normalerweise zum Anzeigen des
- Fehlers von der Standard-Fehlerbehandlung der Shell/GEMError).
- 5.3 Bibliothek: Laufzeitfehler-Behandlung 5 - 29
- ________________________________________________________
-
-
- Hier ein Bespielprogramm:
-
- VAR fehlerAufgetreten: BOOLEAN;
-
- PROCEDURE fehler ( nummer : INTEGER;
- text : ARRAY OF CHAR;
- verursacher: ErrBase.ErrResp;
- abbruch : RtnCond,
- VAR excDaten : Excepts.ExcDesc ): BOOLEAN;
- BEGIN
- IF nummer = MOSGlob.DivByZero THEN
- fehlerAufgetreten:= TRUE;
- RETURN FALSE (* -> Programm fortführen *)
- ELSE
- RETURN TRUE (* -> Fehlermeldung weiterleiten *)
- END
- END fehler;
-
- PROCEDURE modulo ( a,b: CARDINAL; VAR c: CARDINAL; VAR ok: BOOLEAN );
- (* Berechnet den Modulo-Wert v. 'a' und 'b' und liefert die *)
- (* Lösung in 'c'. Bei einen Fehler ('b'=0) ist 'ok' FALSE, *)
- (* sonst TRUE. *)
- VAR stack: ARRAY 1..1000 OF CARDINAL; (* 2 KB Stack reichen *)
- wsp: MOSGlob.MemArea;
- BEGIN
- fehlerAufgetreten:= FALSE;
- wsp.bottom:= ADR ( stack );
- wsp.length:= SIZE ( stack );
- CatchErrors ( fehler, wsp ); (* Fehlerroutine anmelden *)
- (* Jetzt kann gerechnet werden: *)
- c:= a - (a DIV b) * b;
- (* Das reicht. *)
- ReleaseCatcher ( fehler ); (* Fehlerroutine abmelden *)
- ok:= NOT fehlerAufgetreten
- END modulo;
-
- In diesem Beispielprogramm wäre es natürlich einfacher und schneller, b mit
- Null zu vergleichen. Erst in komplexeren Berechnungen lohnt sich das
- Verfahren. Aber mathematische Berechnungen sind nicht das einzige, bei dem
- Fehler in dieser Weise vorteilhaft abgefangen werden können.
- 5.3 Bibliothek: Laufzeitfehler-Behandlung 5 - 30
- ________________________________________________________
-
-
- Wenn nach dem Erkennen des Laufzeitfehlers im obigen Beispiel die fehlerher~
- vorrufende Routine nicht weiter ausgeführt werden darf, sondern gleich aus
- modulo zurückgekehrt werden soll, kann die Funktion so abgeändert werden,
- daß die Berechnung selbst in einer Unterfunktion durchgeführt und diese dann
- mit CallProcess aus ModCtrl aufgerufen wird. In fehler muß dann TermProcess
- mit einem Wert ungleich Null statt "RETURN FALSE" aufgerufen werden. Statt
- über die globale Variable fehlerAufgetreten kann dann über den exitCode von
- CallProcess ein aufgetretener Fehler erkannt werden.
-
- Genauso bietet sich CatchErrors an, wenn einfach verhindert werden soll, daß
- Laufzeitfehler an den Anwender mit einer Bildschirmmeldung gelangen und
- dadurch das Programm unterbrochen wird. Bei Berechnungen mit CARDINAL-
- und INTEGER-Werten reicht es in der Regel, dem Compiler durch die Option
- (*$R-*) im Quelltext mitzuteilen, keine Prüfungen vorzunehmen. Aber z. B. bei
- Benutzung von REAL-Werten werden vorcompilierte Funktionen aus dem Modul
- Runtime importiert, die immer Fehlerprüfungen vornehmen. Hier kann im
- Zweifelsfall nur mit CatchErrors sichergestellt werden, daß das Programm die
- Kontrolle behält.
-
- Ein weiteres Beispiel für die Fehlerbehandlung von Laufzeitfehlern ist das Modul
- GEMError, das Sie als Quelltext erhalten haben. Es ist z.B. in die Shell
- eingebunden und fängt als letztes Modul alle Fehler ab und zeigt sie an. Ein
- gelinktes Programm sollte immer in irgendeiner Weise evtl. auftretende
- Laufzeitfehler abfangen. Am einfachsten ist es, dazu GEMError einzubinden,
- was normalerweise auch geschieht.
-
-
- Dateifehler
-
- Im Kapitel über das Dateisystem wird beschrieben, wie es dazu kommen kann,
- daß eine Fehlermeldung für Dateifehler ausgelöst werden kann. Das Modul
- FileBase enthält die Prozedurvariable HandleError, die aufgerufen wird, wenn
- ein Dateifehler gemeldet werden soll. Wenn sie unverändert bleibt, werden alle
- Dateifehlermeldungen ignoriert.
-
- Das Modul GEMError weist auf HandleError eine Routine zu, die den Fehler
- anzeigt, dem Anwender bei einem Fehler über den Grund und die Programm~
- stelle informiert und ihm die Möglichkeit bietet, das Programm zu beenden,
- fortzuführen oder den Editor aufzurufen, um die Fehlerposition anzuzeigen.
- Dazu wird von HandleError die Dateifehlernummer und die Dateivariable, in
- deren Datei der Fehler auftrat, übergeben. Zusätzlich wird noch ein Argument
- übergeben, das die Adresse der Prozedur im Speicher angibt, an der der
- Dateifehler erkannt wurde.
- 5.3 Bibliothek: Laufzeitfehler-Behandlung 5 - 31
- ________________________________________________________
-
-
- In FileBase findet sich außerdem die Prozedurvariable CloseFile. Sie wird bei
- Programm-/Prozeßende für jede unter dem Prozeß eröffnete und noch offen
- gebliebene Datei aufgerufen. Wird sie nicht verändert, wird jede offen
- gebliebene Datei automatisch geschlossen. GEMError zeigt jedoch alle offenen
- Dateien an und bietet die Möglichkeit, Disk-Dateien, die mit Create angelegt
- wurden, zu löschen. Dies ist von Vorteil, wenn ein Programm, das eine Datei
- erzeugt, durch einen Laufzeitfehler beendet wird. Oft ist dann die erzeugte
- Datei unvollständig und kann gelöscht werden.
-
-
- Fehlerbehandlung mit dem Modul EasyExceptions
-
- Dieses Modul ermöglicht nicht nur die Abfrage von Laufzeitfehlern, eigene
- Fehler können auf einfache Weise selbst ausgelöst werden, und die Funktion, in
- der der Fehler auftrat, kann auf bequeme Weise wieder verlassen werden.
-
- Kernstück der Fehlerkontrolle ist die Funktion Call. Als erstes Argument erhält
- sie die Prozedur, die die eigentliche Operation durchführen soll. Call nimmt alle
- notwendigen Installationen für die Fehlerabfrage vor (über HdlError.CatchErrors)
- und sieht außerdem einen zentralen Rücksprung für alle Fehler vor. Dann
- startet Call die eigentliche Prozedur. Kehrt die Prozedur ohne Fehler zurück,
- liefert Call einen Wert, der den fehlerfreien Ablauf anzeigt. Tritt dagegen ein
- Fehler auf, wird die Prozedur sofort abgebrochen und Call liefert einen
- Fehlerwert.
-
- Die Fehler können nicht nur durch die bereits erwähnten Möglichkeiten
- (RaiseError, CPU-Exception, Soft-Error, Dateifehler), sondern auch über die
- Raise-Funktion aus EasyExceptions gemeldet werden. Die Raise-Funktion hat
- einen entscheidenden Vorteil gegenüber RaiseError: Sie erhält nicht eine
- INTEGER-Zahl, die vorher festgelegt werden muß, sondern einen opaque-Wert,
- welcher vorher über die Funktion New des Moduls angefordert werden muß.
- So können mehrere Funktionen unabhängig voneinander eigene Fehler-Werte
- mit New anfordern. Damit ist gewährleistet, daß es keine Überschneidungen
- bei den Werten gibt. Die Module, die eigene Fehler über Raise auslösen
- können, müssen lediglich Variablen oder Funktionen exportieren, die die
- angeforderten Werte liefern, damit ein Vergleich möglich ist.
-
- Ein Beispielmodul für die Anwendung von EasyExceptions findet sich im DEMO-
- Ordner unter dem Namen EXCTEST.M.
- 5.3 Bibliothek: Laufzeitfehler-Behandlung 5 - 32
- ________________________________________________________
-
-
- Fehlerbehandlung in Accessories
-
- Gerade Accessories sollten auf mögliche oder auch unerwartete Laufzeitfehler
- vorbereitet sein: Sollte ein Accessory tatsächlich einmal unkontrolliert einen
- Laufzeitfehler auslösen, ist der Atari aufgrund der dürftigen Konzeption seiner
- Accessory-Verwaltung zum Stillstand verurteilt: Nichts geht mehr.
-
- Also überlegen Sie es sich gut: Wenn Sie ein Accessory programmieren und
- dies einen Fehler macht, wenn Sie gerade in der Hauptanwendung, z.B. einer
- Textverarbeitung, richtig viele Daten eingegeben haben, ist es doch sicher sehr
- ärgerlich, daß Ihre Daten nicht wegen einem Fehler in der Textverarbeitung,
- sondern wegen einem eigentlich unbeteiligten Programm das Nirwana
- aufgesucht haben, oder?
-
- Da Sie ein vorsichtiger Mensch sind - schließlich haben Sie sich ja für
- Modula-2 und nicht für C entschieden, freut es Sie natürlich besonders, daß
- wir Sie auch hier nicht im Stich lassen: Verwenden Sie einfach die Funktion
- Call aus EasyExceptions, wie dies z.B. im DEMO-Modul AccDemo gezeigt wird.
- Die Funktionen aus HdlError können Sie hier nicht benutzen - sie haben in
- Accessories ohne weiteres keine Wirkung.
- 5.4 Bibliothek: Dateisystem 5 - 33
- ________________________________________________________
-
-
- 5.4 Dateisystem
-
- Das Dateisystem ermöglicht Ein-/Ausgaben von Texten und anderen Daten auf
- Disk (Floppies, Harddisks). Zudem läßt es Textein-/ausgaben auf "sequentielle"
- Einheiten (Device, z. B. Bildschirm, Tastatur, Drucker, Midi-Schnittstelle) zu.
-
- Zum Dateisystem gehören die folgenden Module:
- - Files Öffnen und Schließen von Dateien.
- - Binary Nicht-textuelle Ein-/Ausgabe von Daten auf Diskdateien.
- - Text Textuelle Ein-/Ausgabe auf beliebige Dateien.
- - NumberIO Ein-/Ausgabe von Zahlen in Textform auf beliebige Dateien.
- - InOut Ein-/Ausgabe von Text und Zahlen auf eine Standarddatei.
-
-
-
- Dateimodi
-
- Es gibt zwei verschiedene Modi, um auf eine Datei zuzugreifen. Die beiden
- unterscheiden sich grundsätzlich in der Absicht, was für eine Art von Daten
- bearbeitet werden soll. Entweder wird beabsichtigt, nur normal lesbaren Text
- ein- und auszugeben oder, es sollen Daten (ggf. incl. Text), die in der vom
- Rechner verschlüsselten Form vorliegen, in einer Datei gespeichert werden.
-
- Beispiel: Eine Zahl kann in zwei Formen vorliegen, entweder als String, damit
- sie auf dem Bildschirm anzeigbar ist, oder als rechnerkodierter Wert, z. B. in
- einer CARDINAL-Variable. Nur in der rechnerinternen Form (binär) kann mit
- ihr gerechnet werden, nur die Textform ist für den Anwender lesbar.
- Funktionen wie WriteCard wandeln die in binärer Form übergebene Zahl zur
- Ausgabe erst in einen String um (für Umwandlungen von binär dargestellten
- Zahlen in Strings und umgekehrt gibt es die Module Convert und StrConv).
-
- Zurück zu den zwei Dateimodi. Binäre Daten zu speichern, spart Platz und
- Zeit. Solche kodierten Daten dürfen aber nur in Diskdateien abgelegt, nicht
- jedoch z.B. auf Bildschirm oder Drucker ausgegeben werden.
-
- Soll dagegen ausschließlich Text (also auch Zahlen in Textform) ein- und
- ausgegeben werden, ist das Medium frei wählbar.
- 5.4 Bibliothek: Dateisystem 5 - 34
- ________________________________________________________
-
-
- Öffnen einer Datei
-
- Um auf eine Datei zugreifen zu können, muß man einen Zugriff darauf anmel~
- den. Dies kann mit Open oder Create aus Files geschehen. Dabei wird ein Na~
- me übergeben, der die anzusprechende Datei bezeichnet. Der Name kann dabei
- sowohl ein Disk-Dateiname sein, z. B. "A:ADRESS.DAT", als auch, wenn man
- den rein textuellen Modus wählt, der Name eines sequentiellen Devices. Hierzu
- gehören:
- - "CON:" für Bildschirmausgabe und Tastatureingabe mit gleichzeitiger
- Bildschirmanzeige (mit "Echo"),
- - "KBD:" für Tastatureingabe ohne Echo,
- - "AUX:" für Ein- und Ausgabe über die serielle Schnittstelle,
- - "PRN:" für Ausgabe auf den Druckerport,
- - "MIDI:" für Ein- und Ausgabe über den Midi-Port und
- - weitere selbstdefinierte Namen für eigene Devices, die über die Unit-
- Variablen in FileBase konfiguriert werden können (s.u.).
-
- Beim Öffnen wird außerdem der Zugriffsmodus angegeben. Für den binären
- Zugriff kann writeOnly (nur Schreiben auf Datei), readOnly (nur Lesen) oder
- readWrite(Lesen und Schreiben) angegeben werden. Für textuellen Zugriff ist
- readSeqTxt (nur Lesen), writeSeqTxt (nur Schreiben) oder appendSeqTxt (nur
- Schreiben, bei Diskdateien neue Daten an vorhandene Daten anhängen).
-
- Der Unterschied zwischen Open und Create: Open öffnet stets eine vorhande~
- ne Datei, während Create versucht, eine neue Datei (bei Diskzugriff) anzule~
- gen. Bei Zugriff auf sequentielle Devices, die ja stets schon vorhanden sind,
- sind Open und Create gleichbedeutend.
-
- Create hat noch einen zusätzlichen Parameter, der bestimmt, was passieren
- soll, wenn schon eine Diskdatei unter dem angegebenen Namen existiert. Ist
- dieser Parameter noReplace, heißt das, daß in diesem Fall die vorhandene Datei
- erhalten bleibt und ein Fehler geliefert wird. Ist dagegen replaceOld angegeben,
- wird eine eventuell schon vorhandene Diskdatei gelöscht.
-
- Dazu einige Anwendungsbeispiele:
-
- - Wenn der Zugriffsmodus readOnly oder readSeqTxt ist, wird grundsätzlich
- Open verwendet.
-
- - Wird textuell geschrieben mit dem Modus writeSeqTxt oder appendSeqTxt,
- ist meist Create zu verwenden.
-
- - Wird eine vorhandene Diskdatei mit Open im Modus readWrite, writeOnly
- oder writeSeqTxt geöffnet, überschreiben neu ausgegebene Daten die
- alten von Beginn der Datei an.
- 5.4 Bibliothek: Dateisystem 5 - 35
- ________________________________________________________
-
-
- Bei Open und Close wird als erster Parameter eine Variable vom TypeFile(aus
- Files) erwartet. Diese Variable wird dann von den Funktionen initialisiert und ist
- bei weiteren Dateioperationen stets als erstes Argument anzugeben, um damit
- die geöffnete Datei zu identifizieren. Wenn man also zwei Dateien gleichzeitig
- offen haben will, muß man auch zwei Variablen vom Type File deklarieren und
- je eine für jede Datei verwenden.
-
-
- Ein-/Ausgabe von Daten
-
- Beim Öffnen einer Diskdatei wird ein Dateizeiger angelegt, der zu Beginn auf
- das erste Datum der Datei zeigt, sofern sie nicht leer ist. Ausnahme: Wenn
- der Modus appendSeqTxt ist, zeigt er hinter das Ende der Datei. Werden
- Daten gelesen oder geschrieben, geschieht dies immer ab der aktuellen
- Zeigerposition aufwärts, und der Zeiger wird dabei automatisch erhöht. Wird
- eine Datei auf ein sequentielles Device geöffnet, werden die Textdaten alle in
- Folge gelesen oder geschrieben.
-
- Werden Daten am Ende einer Diskdatei geschrieben, wird die Datei
- automatisch um die erforderliche Datenmenge verlängert.
-
- Für Binärdateien können alle Funktionen aus den Modulen Binary, Text
- (Ausnahme: EOL) und NumberIO verwendet werden. In Binary gibt es
- Funktionen zum Schreiben von beliebigen Daten. So schreibt z. B. WriteWord
- beliebige Daten mit Word-Länge in eine Datei, z. B. CARDINAL-, INTEGER-
- oder Aufzählungstyp-Variablen. Mit WriteBlock können beliebige Daten~
- strukturen geschrieben werden, z.B. RECORDs und ARRAYs. WriteBytes
- erlaubt es, eine Adresse und die Länge eines Datenbereichs zum Schreiben zu
- bestimmen. Ebenso gibt es passende Read...-Funktionen zum Dateilesen.
-
- In Binary gibt es weiterhin die Funktion FileSize, die die aktuelle Länge einer
- Datei in Bytes liefert. Die aktuelle Position des Dateizeigers kann mit FilePos
- ermittelt und mit Seek neu gesetzt werden. Seek bietet sich vor allem in
- Kombination mit dem Zugriffsmodus readWrite an, um in einer Datei, die aus
- vielen gleichartigen, hintereinandergereihten Datenfeldern besteht, einzelne
- Daten herauszugreifen oder zu verändern. Wenn mit Seek der Dateizeiger
- hinter das aktuelle Dateiende positioniert wird, wird die Datei automatisch
- entsprechend erweitert.
-
- Die Module Text und NumberIO enthalten Funktionen zur Textein-/ausgabe, wie
- sie auch in InOut und Terminal vorkommen. Die Funktionen, bis auf EOL aus
- Text, dürfen sowohl im Text- als auch im Binärmodus verwendet werden.
- Allerdings funktioniert die Behandlung des Dateiendes in den beiden Modi
- unterschiedlich.
- 5.4 Bibliothek: Dateisystem 5 - 36
- ________________________________________________________
-
-
- Dateiende-Behandlung
-
- Mittels der Funktion EOF kann ermittelt werden, ob aus einer Datei noch
- weitere Daten gelesen werden können und ob ein Fehler aufgetreten ist.
-
- Während im Textmodus nach Erreichen des Dateiendes die Dateioperationen
- unbedingt beendet werden müssen (da nichts anderes mehr funktioniert), kann
- im Binärmodus, falls mit writeOnly oder readWrite geöffnet wurde, am
- Dateiende geschrieben oder auch mit Seek eine andere Position in der Datei
- erreicht werden.
-
- Auch ist die Funktion EOF im Binärmodus jederzeit aufrufbar, während im
- Textmodus dies nur erlaubt ist, wenn die Datei mit readSeqTxt - jedoch nicht
- mit writeSeqTxt oder appendSeqTxt - geöffnet wurde.
-
- Im Binärmodus zeigt EOF dann das Dateiende an, wenn der Dateizeiger genau
- auf das Ende der Datei zeigt. So kann also schon vor einem Lesezugriff mit
- dieser Funktion ermittelt werden, ob überhaupt noch Daten vorhanden sind.
-
- Im Textmodus gibt es nicht unbedingt einen Dateizeiger, denn der existiert ja
- nur bei Diskdateien, aber nicht bei sequentiellen Devices. Deshalb erfolgt hier
- die Dateiendeerkennung auf eine andere Weise, und zwar mit einem
- bestimmten Dateiendezeichen. Die Lesefunktionen prüfen jedes gelesene
- Zeichen. Ist es das Dateiendezeichen, ist automatisch das Dateiende erreicht.
- Daraus folgt, daß erst ein Zeichen gelesen werden muß, bevor das Dateiende
- erkannt werden kann.
-
- Bei Textdateien auf Disk wird zusätzlich überprüft, ob der Dateizeiger das
- Dateiende erreicht hat, damit es keine Probleme gibt, wenn eine Diskdatei
- gelesen wird, die kein Dateiendezeichen enthält.
-
- Es gibt zwei Gruppen von Lesefunktionen, bei denen diese Unterschiede beach~
- tet werden müssen. Auf der einen Seite die Read-Funktion, auf der anderen
- die ReadString-Funktion und die Funktionen aus NumberIO.
-
- Die Read-Funktion ist leicht durchschaubar. Im Textmodus muß nach einem
- Lesezugriff geprüft werden, ob das Dateiende erreicht ist. In dem Fall ist das
- gelesene Zeichen nicht mehr zu verwenden, denn es ist lediglich das Ende~
- kennzeichen.
-
- Bei ReadString ist der erhaltene String verwendbar, es ist lediglich das Ende~
- kennzeichen nicht darin enthalten. Bei den Lesefunktionen aus NumberIO ist die
- Zahl gültig, sofern deren success-Argument TRUE ist.
- 5.4 Bibliothek: Dateisystem 5 - 37
- ________________________________________________________
-
-
- Als Beispiel je eine Leseschleife für den Binär- und den Textmodus:
-
- (* Für Binärdateien *)
- WHILE NOT Files.EOF (f) DO (* EOF schon vor Zugriff bekannt *)
- Text.Read (f, ch);
- Verarbeite (ch)
- END;
-
- (* Für Textdateien *)
- LOOP
- Text.Read (f, ch);
- IF Files.EOF (f) THEN EXIT END;
- (* EOF wird erst nach Lesen erkannt *)
- Verarbeite (ch) (* 'ch' nur gültig, wenn kein EOF *)
- END;
-
- Bei Dateien, die zum textuellen Lesen eröffnet sind, ist außerdem die Funktion
- EOL benutzbar. Sie signalisiert, wenn ein Zeilentrennzeichen gelesen wurde,
- das Dateiende erreicht oder ein Fehler aufgetreten ist. Ebenso wie das
- Dateiende kann auch das Zeilenende erst nach dem Lesezugriff erkannt
- werden und, bei Read ist dann ebenfalls das erhaltene Zeichen zu verwerfen.
-
- Das Zeilentrennzeichen ist ein einzelnes CR (15C) oder ein CR mit einem direkt
- folgenden LF. Das Anwenderprogramm braucht also nicht selbst zu
- unterscheiden, ob die Eingabe z. B. von Tastatur kommt, wo normalerweise
- allein mit CR die Zeile begrenzt wird, oder von einer Datei, die meist (nicht
- immer) mit CR und LF eine Zeile abschließt. Das eventuelle LF-Zeichen nach
- einem CR kann beim textuellen Lesen nicht erhalten werden.
-
- Es folgt ein Programmbeispiel für textuelles Lesen einer Datei mit Read:
- 5.4 Bibliothek: Dateisystem 5 - 38
- ________________________________________________________
-
-
- MODULE TestPrg;
-
- IMPORT Files, InOut;
-
- PROCEDURE LeseUndDruckeText (textname: ARRAY OF CHAR);
-
- PROCEDURE MeinFehlerTest (f: Files.File);
- VAR msg: ARRAY 0..31 OF CHAR;
- BEGIN
- IF Files.State (f) < 0 THEN (* ernster Fehler ? *)
- Files.GetStateMsg (Files.State (f), msg);
- (* Fehlertext holen *)
- Files.ResetState (f); (* Fehler rücksetzen *)
- InOut.WriteLn;
- InOut.WriteString (msg); (* Fehlertext anzeigen *)
- END
- END MeinFehlerTest;
-
- VAR f: Files.File; ch: CHAR;
-
- BEGIN
- Files.Open (f, textname, Files.readSeqTxt);
- IF Files.State (f) >= 0 THEN
- LOOP
- Text.Read (f, ch);
- IF Text.EOL (f) THEN (* Zeichen ungültig *)
- IF Text.EOF (f) THEN
- MeinFehlerTest (f); (* Fehler ? *)
- EXIT (* Auf jeden Fall Ende *)
- ELSE
- InOut.WriteLn (* Zeilenende *)
- END
- ELSE
- InOut.Write (ch); (* gelesenes Zeichen ausgeben *)
- END
- END;
- Files.Close (f)
- END
- END LeseUndDruckeText;
-
- BEGIN (* of main *)
- LeseUndDruckeText ("KBD:"); (* Eingabe von Tastatur *)
- LeseUndDruckeText ("A:TEST.TXT") (* Eingabe v. Diskdatei *)
- END TestPrg.
- 5.4 Bibliothek: Dateisystem 5 - 39
- ________________________________________________________
-
-
- Die Leseschleife kann auch noch eleganter programmiert werden:
-
- LOOP
- Text.Read (f, ch);
- CASE State (f) OF (* siehe Kap. über Fehlerbehandlung *)
- MOSGlobals.fOK : InOut.Write (ch)| (* Zeichen ausg. *)
- MOSGlobals.fEOL: InOut.WriteLn| (* Zeilenende *)
- MOSGlobals.fEOF: EXIT (* Dateiende *)
- ELSE
- MeinFehlerTest (f);EXIT
- END
- END;
-
- Wie aus dem Beispiel ersichtlich ist, müssen Zeilenbegrenzer (CR und/oder LF)
- über die Funktion EOL abgefragt werden. Dazu muß vorher ein Lesezugriff
- erfolgt sein. Das gleiche gilt für die Dateiende-Erkennung. Liefert die Funktion
- EOF TRUE, dann kann mit Hilfe der Funktion State erkannt werden, ob das
- Dateiende (State(f)>=0) erreicht wurde oder ob ein Fehler aufgetreten ist
- (State(f)<0).
-
- Als letztes Beispiel die Read-Routine angepaßt für ReadString:
-
- VAR s:ARRAY 0..9 OF CHAR;
-
- ...
-
- LOOP
- Text.ReadString (f,s);
- InOut.WriteString (s);
- (* Der String ist auf jeden Fall *)
- (* brauchbar, ggf. ist er leer. *)
- IF Text.EOL (f) THEN
- IF Files.EOF (f) THEN (* Entweder Fehler o. Dateiende *)
- MeinFehlerTest (f); (* Fehler ? *)
- EXIT (* Auf jeden Fall Ende *)
- ELSE (* Zeilenende: *)
- InOut.WriteLn
- END
- END
- END;
- 5.4 Bibliothek: Dateisystem 5 - 40
- ________________________________________________________
-
-
- Diverse Dateifunktionen (Modul "Files")
-
- Am Ende aller Zugriffe auf eine Datei sollte sie mit Close geschlossen werden.
- Vor allem bei Diskdateien, die beschrieben wurden, ist dies unbedingt
- erforderlich. Wenn Sie dies vergessen, wird bei Modulen, die von der Shell
- gestartet wurden oder in die das Modul GEMError eingebunden ist, bei
- Prozeßende eine Meldung angezeigt, die auf offen verbliebene Dateien hinweist
- und sie ordnungsgemäß schließt.
-
- Ist ein fataler Fehler aufgetreten und will man bereits erzeugte Daten
- verwerfen, kann Remove statt Close aufgerufen werden. Dann werden
- Diskdateien, die mit Create erzeugt wurden, wieder gelöscht, mit Open
- geöffnete Dateien werden normal, wie mit Close, geschlossen.
-
- Mit SetEOFMode kann ausschließlich bei Textdateien bestimmt werden, ob und
- mit welchem Zeichen das Dateiende erkannt werden soll. GetEOFMode
- ermittelt die augenblickliche Einstellung für eine offene Datei. Normalerweise
- wird beim Lesen des üblichen ASCII-Zeichens "ETX" (32C, $1A) das Dateiende
- erkannt.
-
- Flush wird nur bei Ausgabedateien benötigt. Es sorgt für eine unbedingte
- Speicherung bzw. Übermittelung der ausgegebenen Daten. Denn es ist möglich,
- daß die ausgegebenen Daten zuerst in einem rechnerinternen Speicherbereich
- gesammelt werden, bevor sie auf Disk geschrieben oder z. B. über die serielle
- Schnittstelle ausgegeben werden, damit eine höhere Ausgabegeschwindigkeit
- erreicht werden kann. Nur nach dem Aufruf von Flush oder Close ist
- sichergestellt, daß die Daten ihr Ziel erreicht haben. Normalerweise werden
- also die Daten in einem normalen Ablauf immer ankommen, nur gibt es Fälle, in
- denen dies zu einem bestimmten Zeitpunkt gesichert sein muß. Mit anderen
- Worten: Wenn Sie nicht wissen, wofür diese Funktion gut ist, dann werden Sie
- sie auch nicht brauchen. Mir fällt noch etwas ein: Beispielsweise wartet Flush
- bei einer Datei, die auf "AUX:" geöffnet ist, bis alle Daten des Seriell-
- Datenpuffers ausgegeben sind.
-
- SetDateTimeund GetDateTime setzen bzw. erfragen die Zeitangabe einer
- Datei. Bei nicht-Diskdateien wird SetDateTime ignoriert und bei GetDateTime
- ein Null-Datum geliefert.
-
- Mit GetFileName kann man den Namen, mit dem eine Datei eröffnet wurde,
- ermitteln. Ist die Datei nicht offen, wird ein Leername geliefert.
- 5.4 Bibliothek: Dateisystem 5 - 41
- ________________________________________________________
-
-
- Fehlerbehandlung im Dateisystem
-
- Selbstverständlich sollte man nach Aufruf jeder Dateibearbeitungsfunktion
- eventuell aufgetretene Fehler prüfen. Dies geschieht durch Aufruf der Funktion
- State, die einen INTEGER-Wert liefert. Liefert sie einen negativen Wert,
- bedeutet dies, daß bei der letzten Dateioperation ein Fehler auftrat. Die
- Fehlernummer entspricht den TOS-Fehlernummern. Des weiteren erzeugen die
- MOS-Funktionen eigene Fehlernummern, die daran erkennbar sind, daß sie alle
- niedriger als -127 sind. Alle Fehlernummern sind im Modul MOSGlobals
- definiert und kurz erklärt.
-
- Wird nun aus Nachlässigkeit beim Programmieren ein aufgetretener Fehler
- beim Dateizugriff nicht abgefragt und somit nicht erkannt, wird, sofern das
- Modul GEMError vorhanden ist, beim nächsten Aufruf einer Dateibehandlungs~
- funktion das laufende Programm unterbrochen und eine Fehlermeldung
- angezeigt, woraufhin das Programm beendet oder fortgeführt werden kann,
- wahlweise mit Ignorieren des Fehlers, so daß er weiterhin bestehen bleibt,
- oder mit Rücksetzen des Fehlers, damit weitere Dateifunktionen nicht
- wiederholt den Fehler anzeigen.
-
- Solange Sie nur kleine Programme entwickeln, reicht es auch aus, nur dort
- Fehlerabfragen zu programmieren, wo ständig mit Fehlern gerechnet werden
- muß: z. B. nach dem Öffnen einer Datei, um zu erfahren, ob die Datei
- vorhanden ist, oder vor allem nach Close, da hier die automatische
- Fehlermeldung nicht mehr zuschlagen kann. Dagegen ist es ganz legitim und
- auch bequemer, in schnell geschriebenen Programmen Fehlerabfragen und
- -meldungen nach Lese- und Schreiboperationen dem MOS zu überlassen.
-
- Die automatische Fehlerprüfung wird von allen Dateifunktionen durchgeführt,
- außer Open, Create, EOF, EOL, State, ResetState, GetStateMsg, GetFileName,
- SetEOFMode und GetEOFMode.
-
- Die folgenden Funktionen des Dateisystems können keine Fehler auslösen. Nach
- Aufruf dieser Funktionen ist es also nicht nicht notwendig, zu prüfen, ob ein
- Fehler aufgetreten ist: EOF, EOL, FileSize, FilePos, SetEOFMode, GetEOFMode,
- GetFileName, State, ResetState und GetStateMsg.
-
- Wird ein Fehler vom Programm erkannt, muß es zuerst den Fehler mit der
- Funktion ResetState rücksetzen, damit es nicht zu einer Fehlermeldung beim
- nächsten Aufruf einer Dateifunktion kommt.
- 5.4 Bibliothek: Dateisystem 5 - 42
- ________________________________________________________
-
-
- Die Funktion State liefert demnach einen positiven Wert, wenn bisher kein
- Fehler aufgetreten ist. In der Regel wird eine Null geliefert, jedoch kann es
- auch vorkommen, daß ein Wert größer Null erhalten wird. Dies signalisiert
- dann besondere Zustände. Z. B. erhält man den Wert Drei, wenn Close für
- eine bereits geschlossene Datei aufgerufen wurde, denn dies ist kein Fehler,
- aber es kann auf der anderen Seite auch interessant sein. Außerdem kann der
- Wert Eins oder Zwei geliefert werden, wenn ein Zeilenende oder das Dateiende
- erreicht worden ist. Dies kann dadurch die Verwendung von EOF und EOL
- ersetzen.
-
- Im allgemeinen empfiehlt sich daher, nach einer Dateioperation Fehler daran zu
- erkennen, ob die Funktion State einen positiven oder negativen Wert liefert,
- und nicht daran, ob State den Wert Null liefert!
-
-
- Zusammenfassung der Unterschiede zwischen Binär- und Textmodus
-
- Binärdateien (readOnly, writeOnly, readWrite):
- - Es darf nur auf Disk (Floppies, Harddisks oder andere Random Access
- Devices) zugegriffen werden.
- - Die Funktion EOF liefert schon vor einem Zugriff, ob der Dateizeiger am
- Dateiende steht.
- - Die Funktion EOL darf nicht verwendet werden.
-
- Textdateien (readSeqTxt, writeSeqTxt, appendSeqTxt):
- - Es dürfen keine Funktionen aus Binary (Dateizeigeroperationen, byte-
- weises Lesen/Schreiben, Dateilängenermittlung) verwendet werden.
- - Die Funktion EOF darf nicht auf Dateien angewandt werden, die zur
- Ausgabe eröffnet wurden. Sie liefert erst nach einem Lesezugriff, ob
- noch weitere Daten folgen.
- 5.4 Bibliothek: Dateisystem 5 - 43
- ________________________________________________________
-
-
- Das Modul InOut
-
- Die Funktionen in diesem Modul vereinfachen die Dateiein-/ausgabe. Man
- braucht sich um die Fehlerabfragen und die Besonderheiten der Dateibehand~
- lung nicht zu kümmern. Normalerweise ist immer je eine Datei für Ein- und
- Ausgabe über Tastatur und Bildschirm (Textwindow) geöffnet. Es stehen alle
- üblichen Funktionen für textuelle Ein- und Ausgaben zur Verfügung. Da alle
- Ein-/Ausgaben auf jeweils eine Standarddatei gehen, braucht bei den Funktionen
- keine Dateikennung (File-Variable) übergeben zu werden.
-
- Mit RedirectInput und RedirectOutputkann eine Datei bestimmt werden, auf die
- die folgenden Ein- oder Ausgaben gelenkt werden. Letztere Funktion hat neben
- dem Dateinamen einen weiteren Parameter, der bestimmt, ob die Datei mit
- writeSeqTxt oder appendSeqTxt geöffnet werden soll.
-
- OpenInput und OpenOutput geben auf dem Bildschirm einen Text aus, der dazu
- auffordert, einen Dateinamen einzugeben. Tritt beim Öffnen der Datei dann ein
- Fehler auf, wird eine Fehlermeldung ausgegeben und man hat die Wahl, ob die
- Dateibestimmung wiederholt werden soll. Bei OpenOutput hat man weiterhin die
- Möglichkeit, durch Eingabe eines ">" vor dem Dateinamen zu bestimmen, daß
- die folgenden Daten an die angegebene Diskdatei angefügt werden sollen. Wird
- dies nicht bestimmt, darf die Ausgabedatei nicht schon bestehen, sonst erfolgt
- eine Fehlermeldung.
-
- Alle vier Funktionen signalisieren über die Variable Done, ob das Öffnen der
- Datei funktionierte. Wenn ein Fehler auftrat oder ein Leerstring bei OpenInput/
- Output eingegeben wurde, erfolgen die weiteren Ein-/Ausgaben über Tastatur
- bzw. Bildschirm. Done ist dann FALSE. War vor Aufruf einer der vier
- Funktionen bereits Ein-/Ausgabe umgelenkt, wird die alte Datei zuerst
- geschlossen.
-
- Die Ein- oder Ausgabeumleitung können Sie auch vom Anwender bestimmen
- lassen, indem Sie das Modul ArgCVIO importieren und die darin enthaltene
- Funktion InitArgCVaufrufen. Wenn Sie dann das Programm starten, können Sie
- als Argumentzeile z. B. ">PRN:" angeben, um die Ausgaben auf den Drucker zu
- leiten, oder "<IN.TXT >>OUT.TXT", damit die Eingaben aus der Datei "IN.TXT"
- geholt und die Ausgaben an die Datei "OUT.TXT" angefügt werden.
-
- CloseInput und CloseOutput oder ein Fehler während des Dateizugriffs
- schließen die betroffene Datei und lenken die Ein- bzw. Ausgabe wieder auf
- Tastatur bzw. Bildschirm.
-
- Done zeigt nach den Zahleneingabefunktionen an, ob der eingegebene Wert
- gültig ist. termCH enthält nach denselben Funktionen oder nach ReadString das
- Zeichen, durch das die Zahlen- oder Texteingabe beendet wurde.
- 5.4 Bibliothek: Dateisystem 5 - 44
- ________________________________________________________
-
-
- Konfiguration eigener Unittreiber
-
- Im Modul FileBase ist ein Array namens UnitDriver deklariert. Jedes der Feld~
- elemente enthält einen Namen, Prozedurvariablen und weitere Daten für ein
- über das Dateisystem ansprechbares sequentielles Device (Unit).
-
- Das erste Feld z. B. enthält den Unitnamen "CON:" und die Informationen, daß
- diese Unit sowohl Ein- als auch Ausgaben zuläßt. Dazu sind auf die Prozedur~
- variablen für zeichenweise Ein- und Ausgabe Hilfsprozeduren zugewiesen, die
- die Zeichen über die BIOS-Funktionen des TOS weiterleiten. Weitere Felder
- sind für "AUX:", "PRN:", "KBD:" und "MIDI:" initialisiert. Erfreulicherweise sind
- auch noch sieben freie Felder vorgesehen.
-
- Diese Initialisierungen werden immer vom FileBase-Modul vorgenommen. Es ist
- nun aber möglich, die Ein-/Ausgabefunktionen der bestehenden Units zu ändern
- oder auch weitere Units in die freien Feldern einzutragen. Sollten Sie bei~
- spielsweise verbesserte Routinen für die serielle Schnittstelle erstellt haben,
- können Sie Ihre eigenen Prozeduren gegen die Standardroutinen austauschen,
- ohne daß Programme, die die serielle Schnittstelle über das Modula-Datei~
- system mit "AUX:" ansprechen, geändert werden müssen.
-
- Wie Sie Ihre Routinen resident einbinden, erfahren Sie am Ende des Kapitels
- über Prozesse.
- 5.5 Bibliothek: Grafikdarstellung im Atari ST 5- 45
- ________________________________________________________
-
-
- 5.5 Grafikdarstellung im Atari ST
-
-
- Alles, was auf dem Bildschirm zu sehen ist, wird im Speicher des Rechners
- durch ein Bitraster repräsentiert. Dieses Bitraster belegt 32 kByte und ist in
- planes, was soviel wie Bitebene bedeutet, unterteilt. Aus der Anzahl der Bit~
- ebenen läßt sich leicht die Zahl der gleichzeitig (ohne Tricks) darstellbaren
- Farben errechnen. Es ist
-
- Anzahl der Bitebenen
- Zahl der Farben = 2
- .
-
-
- Beim ST kommen normalerweise drei verschiedene Modi vor:
-
- hohe Auflösung: Es ist nur eine Bitebene vorhanden, woraus sich die Anzahl
- 1
- der Farben zu 2 = 2 ergibt. Dieser Modus wird auch monochrome (schwarz/
- weiße) Darstellung genannt und erlaubt es, 640 x 400 einzelne Pixel (Bildpunkte)
- anzusteuern;
-
- 2
- mittlere Auflösung: Zwei Bitebenen stehen zur Verfügung, was zu 2 = 4 ver~
- schiedenen Farben führt. Bei dieser Darstellungsart können noch 640 x 200
- Pixel benutzt werden. Das heißt jede Bitebene ist 640 Pixel breit und 200 Pixel
- hoch;
-
- 4
- niedrige Auflösung: Das Raster wird in vier Bitebenen aufgeteilt, wobei 2 = 16
- Farben erlaubt sind. Allerdings hat eine Bitebene dann nur noch 320 x 200
- Punkte.
-
- Bei den mehrfarbigen Darstellungsmodi kann jede Farbe aus einer Palette von
- 512 verschiedenen Farben ausgewählt werden.
-
-
- Da der Atari ST keinen speziellen Textmodus besitzt, muß auch Schrift durch
- ein Bitmuster repräsentiert werden. Dafür existieren verschiedene Zeichen~
- sätze (fonts), die das Aussehen der einzelnen Schriftzeichen festlegen. Ist ein
- Zeichensatz unproportional, so besitzen alle Zeichen die gleiche Breite. Bei
- einem proportionalen Font können zwei verschiedene Zeichen hingegen auch
- unterschiedliche Breite haben (Dieser Text wurde zum Beispiel mit einem
- proportionalen Zeichensatz geschrieben). Das Betriebssystem stellt drei unpro~
- portionale, sogenannte Systemfonts, zur Verfügung. Deren Ausmaße betragen
- 6 x 6, 8 x 8 und 8 x 16 Pixel. Der 6 x 6 Zeichensatz wird normalerweise für
- die Beschriftung von Icons (Piktogrammen) verwendet. Die beiden anderen
- dienen der allgemeinen Darstellung von Schrift, wobei der 8 x 16 Font für die
- 5.5 Bibliothek: Grafikdarstellung im Atari ST 5- 46
- ________________________________________________________
-
-
- hohe und der 8 x 8 Font für die mittlere und niedrige Auflösung gedacht ist.
- Daraus errechnet man sofort, daß bei hoher und mittlerer Auflösung 80 x 25
- und bei niedriger 40 x 25 Zeichen angezeigt werden können. Bei der Darstel~
- lung von Schrift muß zwischen den Ausmaßen des eigentlichen Zeichens und
- denen der Zeichenzelle (auch Zeichenbox) unterschieden werden. Die Größe
- der Zeichenzelle eines Zeichens des 8 x 16 Fonts beträgt eben genau 8 x 16
- Pixel, die Größe des Zeichens selber, zum Beispiel eines kleingeschriebenen i,
- ist in der Regel aber geringer. Eine Zeichenzelle wird durch einige horizontale
- Linien unterteilt, von denen die wichtigste die base line (Grundlinie) ist, welche
- bestimmt, in welcher Höhe die Zeichen ohne Unterlängen aufliegen.
- 5.6 Bibliothek: Die Line A-Routinen 5- 47
- ________________________________________________________
-
-
- 5.6 Die Line A-Routinen
-
- Die Line A-Routinen stellen eine Sammlung von grafischen Grundfunktionen dar.
- Der Name der Routinen leitet sich von der Art und Weise ihres Aufrufes ab.
- Sie werden nämlich durch Opcodes der Form $Axxx aufgerufen, die im 68000
- eine Ausnahmebehandlung (Exception) auslösen.
-
- Dieser Aufruf auf Maschinenebene muß vom Modula-Programmierer natürlich
- nicht mehr durchgeführt werden. Statt dessen importiert er die entsprechen~
- den Prozeduren aus dem Modul LineA. Da ein Großteil der Parameter (zum
- Beispiel Schreibmodus und Farbe) entsprechend einem $Axxx-Aufruf in einem
- globalen Variablenbereich, den sogenannten Line A-Variablen, definiert werden
- muß, gehört das Modul noch zu den Low-Level-Modulen. Aus diesem Grund
- wird auch die Benutzung der komplexeren und komfortableren VDI-Routinen
- empfohlen. Nur in Sonderfällen sollte auf die Line A-Funktionen zurückgriffen
- werden - keinesfalls sollten VDI- und Line A-Aufrufe in einem Programm
- vermischt werden, da dies zu Inkompatibilitäten in folgenden Grafik~
- erweiterungen (z.B. Ganzseitenbildschirm, höher auflösende Farbgrafik) führen
- kann. Zur Entscheidungshilfe sei auf die Fachliteratur verwiesen (z.B. das Atari
- ST Profibuch aus dem Sybex-Verlag). Die genaue Beschreibung der Routinen
- steht im Anhang B. Hier sollen nur noch die verwendeten Datenstrukturen
- erklärt werden.
-
-
- Der Font-Header
-
- Die Muster aller Zeichen eines Zeichensatzes liegen in einem einzigen, aus ei~
- ner Bitebene bestehenden Bitraster. Dort sind die Zeichen nebeneinander an~
- geordnet, woraus folgt, daß die Breite des Rasters genau die Summe aller
- Zeichenbreiten ist. Eine Zeile des Bitrasters wird auch als Scan-Zeile bezeich~
- net. Die Anzahl der Scan-Zeilen entspricht der Höhe einer Zeichenbox, also
- der maximalen Höhe eines Zeichens.
-
- Um die Breite eines einzelnen Zeichens zu ermitteln, geht man folgendermaßen
- vor: Man zieht vom ASCII-Wert des fraglichen Zeichens den ASCII-Wert des
- ersten darstellbaren Zeichens (siehe minADE) ab. Die erhaltene Zahl stellt ei~
- nen Feldindex für die Character-Offset-Tabelle dar. Aus dieser liest man den
- indizierten und den darauf folgenden Wert. Subtrahiert man nun den ersten
- von dem zweiten erhaltenen Wert, so ergibt sich das gewünschte Ergebnis.
- Außerdem entspricht der indizierte Wert auch der x-Koordinate des Zeichens
- innerhalb des Bitrasters, welches die Font-Daten enthält.
-
- Die Horizontale-Offset-Tabelle wird, falls vorhanden, wie die Character-Offset-
- Tabelle indiziert und enthält einen vorzeichenbehafteten Wert, um den das Zei~
- chen bei der Ausgabe verschoben werden soll. Der Font-Header ist in Form
- eines Verbundes (FontHeader) definiert. Die Verbund-Komponeten haben fol~
- gende Bedeutung:
- 5.6 Bibliothek: Die Line A-Routinen 5- 48
- ________________________________________________________
-
-
- Bezeichner Bedeutung
-
- id Identifikationsnummer des Zeichensatzes
- size Größe des Fonts in Punkt (Maß aus der Satztechnik)
- name Name des Zeichensatzes
- minADE Niedrigster im Zeichensatz enthaltener ASCII-Wert
- maxADE Höchster im Zeichensatz enthaltener ASCII-Wert
- topToBase Abstand zwischen top line und base line
- ascentToBase Abstand zwischen ascent line und base line
- halfToBase Abstand zwischen half line und base line
- descentToBase Abstand zwischen descent line und base line
- bottomToBase Abstand zwischen bottom line und base line
- maxCharWidth Maximale Zeichenbreite
- maxBoxWidth Maximale Breite einer Zeichenzelle
- leftOffset Linker Offset für Kursivschrift
- rightOffset Rechter Offset für Kursivschrift
- thickening Anzahl der Pixel, um die ein einzelnes Zeichen bei der
- Darstellung fetter Schrift verbreitert werden soll
- underLineH Höhe des Striches für Unterstreichungen, in Pixel
- lightMask Maske zur Erzeugung aufgehellter Schrift
- (normalerweise $5555)
- skewMask Maske zur Erzeugung schräger (kursiver) Zeichen
- (normalerweise $5555)
- flags Die einzelnen Bits haben folgende Bedeutung:
- Bit 0 -- Zeigt an, daß der Header zum Systemzeichen~
- satz gehört
- Bit 1 -- Zeigt an, daß die Horizontale-Offset-Tabelle
- benutzt wird
- Bit 2 -- Zeigt an, daß die Font-Daten im 68000-Format
- (Low/High Byte) vorliegen, sonst im Intel-For~
- mat (High/Low Byte)
- Bit 3 -- Zeigt an, daß alle Zeichen des Fonts gleich breit
- sind (also keine Proportionalschrift)
-
- horOffsetTab Zeiger auf die Horizontale-Offset-Tabelle (falls diese
- vorhanden ist)
- charOffsetTab Zeiger auf die Character-Offset-Tabelle
- fontData Zeiger auf das Bitraster, das die Bitmuster der Zeichen
- enthält
- formWidth Breite einer Scan-Zeile, also die Summe aller Zeichen~
- breiten
- formHeight Anzahl der Scan-Zeilen
- next Zeiger auf den Font-Header des nächsten Zeichensatzes
- 5.6 Bibliothek: Die Line A-Routinen 5- 49
- ________________________________________________________
-
-
- Die Line A-Variablen
-
- Die Line A-Variablen dienen zur Übergabe der Parameter an die Line A-Routi~
- nen. Welche Variablen von einer Routine ausgewertet werden, ist bei der Be~
- schreibung der betreffenden Prozedur angegeben (Siehe Anhang B).
-
- Es folgt eine Erklärung aller Line A-Variablen. Die Variablen sind in einem Ver~
- bund mit dem Bezeichner LineAVars zusammengefaßt, der folgende Struktur
- hat:
-
- Bezeichner Bedeutung
-
- planes Gibt die Anzahl der benutzten Bitebenen an. Wird von je~
- der Routine, außer BitBlockTransfer, ausgewertet
- bytesPerLine Anzahl der Bytes einer Bildschirmzeile (Scan-Zeile). Wird
- von jeder Routine, außer BitBlockTransfer,ausgewertet
- contrl Zeiger auf das CONTRL-Array
- intin Zeiger auf das INTIN-Array
- ptsin Zeiger auf das PTSIN-Array
- intout Zeiger auf das INTOUT-Array
- ptsout Zeiger auf das PTSOUT-Array
- plane1 Gibt an, welchen Wert das Bit der ersten Bitebene beim
- Setzen eines Punktes erhalten soll
- plane2 Gibt an, welchen Wert das Bit der zweiten Bitebene beim
- Setzen eines Punktes erhalten soll
- plane3 Gibt an, welchen Wert das Bit der dritten Bitebene beim
- Setzen eines Punktes erhalten soll
- plane4 Gibt an, welchen Wert das Bit der vierten Bitebene beim
- Setzen eines Punktes erhalten soll
- lastLine Wird beim Zeichnen von Linien ausgewertet und besagt,
- ob die zu zeichnende Linie Teil eines im EXCLUSIV-
- ODER-Schreibmodus gezeichneten Polygonzuges ist. TRUE
- bedeutet "Linie vollständig zeichnen"
- lineMask Bitmuster für das Zeichnen von Linien
- writingMode Gibt an, in welchem Schreibmodus gezeichnet werden soll.
- Siehe auch GrafBase.WritingMode
- p Erster Punkt
- q Zweiter Punkt
- patternPtr Zeigt auf das zu verwendende Füllmuster. Ein Füllmuster
- besteht aus einer oder mehreren Bitebenen, die immer 16
- Bit (also ein Wort) breit sind.
- patternMask Gibt an, wie viele Zeilen eine Bitebene des Füllmusters
- n
- besitzt. Sinnvoll sind nur Zahlen, die sich durch 2 (n >
- 0) dar-stellen lassen.
- multiFill Ist diese Variable gesetzt, so besteht das Füllmuster aus
- mehreren Bitebenen, sonst nur aus einer.
- 5.6 Bibliothek: Die Line A-Routinen 5- 50
- ________________________________________________________
-
-
- clipping Gibt an, ob der folgende Rechteckbereich als Ausgabebe~
- grenzung benutzt werden soll. In diesem Fall werden alle
- Punkte, die ausserhalb dieses Bereichs zu liegen kom~
- men, unterdrückt.
- minClip Linker, oberer Punkt des Begrenzungsrechtecks
- maxClip Rechter, unterer Punkt des Begrenzungsrechtecks
- scaleAcc Dient als Startwert für den Schriftvergrößerungs- und
- verkleinerungsalgorithmus. Sollte bei gesetztem scale-Flag
- (Siehe unten) mit $8000 vorbesetzt werden.
- scaleFactor Gibt den Vergrößerungs- oder Verkleinerungsfaktor an.
- Dabei gilt für die
- Vergrößerung: $0000 - Normale Größe
- .
- . Entsprechende Zwischengrößen
- .
- $FFFF - Doppelte Größe
- Verkleinerung: $0000 - Keine Größe (Schrumpfung auf
- . einen Punkt)
- . Entsprechende Zwischengrößen
- .
- $FFFE - Normale Größe
- scaleMode
- Gibt an ob vergrößert oder verkleinert werden soll. Ist
- Bit 0 gesetzt, so wird vergrößert, sonst wird verkleinert
- monoStatus Zeigt an, daß die Zeichen einheitliche Breite haben. Ist
- bei proportionalen Fonts nicht der Fall
- source Linke, obere Ecke des Zeichens im Bitraster des Fonts
- dest Linke, obere Ecke des Zeichens auf dem Bildschirm
- width Breite des Zeichens
- height Höhe des Zeichens
- formBase Zeiger auf den Anfang der Font-Daten (Bitraster des Fonts)
- formWidth Breite einer Scan-Zeile im Bitraster des Fonts (Angabe
- in Bytes)
- style Flags für spezielle Texteffekte. Es bedeutet:
- Bit 0 -- Fette Darstellung der Schrift
- Bit 1 -- Aufgehellte Darstellung der Schrift
- Bit 2 -- Schrägstellen der Schrift (Kursive Darstellung)
- Bit 3 -- Unterstreichen der Schrift
- Bit 4 -- Umrahmte Darstellung der Schrift
- lightMask Maske zum aufgehellten Darstellen der Schrift
- skewMask Maske für kursive Schrift
- weight Anzahl der Bits, um die fette Schrift verbreitert werden
- soll
- rightOff Rechter Offset für kursive Schrift
- leftOff Linker Offset für kursive Schrift
- 5.6 Bibliothek: Die Line A-Routinen 5- 51
- ________________________________________________________
-
-
- scale Zeigt an, ob Schrift in ihren Ausmaßen verändert werden
- soll
- chup Gibt den Winkel zwischen der Zeichengrundlinie (base line)
- und der horizontalen Koordinatenachse, entgegen dem
- Uhrzeigersinn an. Dabei bedeutet (Zwischenwerte sind
- nicht möglich):
- 0 -- Normale Darstellung
- 900 -- Drehung um 90 Grad
- 1800 -- Drehung um 180 Grad
- 2700 -- Drehung um 270 Grad
- textFg Vordergrundfarbe für die Textdarstellung
- scratchArea Zeiger auf einen Speicherbereich, der bei der Vergrößer~
- ung/Verkleinerung von Schrift und für Texteffekte ver~
- wendet wird
- scratchOff2 Offset für den obigen Zeiger, falls sowohl eine Größen~
- änderung als auch Texteffekte erwünscht sind
-
- Zu den beiden vorangegangenen Variablen ist folgendes zu sagen. Beim Durch~
- führen einer Größenänderung von Schrift werden
-
- Breite 2
- 8 5
- Höhe * ( ------- + 2) * ( Faktor + 1)
- 8 5
- 8
-
- Bytes von den Line A Routinen benötigt.
-
- Es stehen Höhe und Breite für die Ausmaße der Zeichenzelle im Originalzu~
- stand (in Pixel). Faktor gibt den Vergrößerungsfaktor an (Faktor = 1.5 bedeutet
- zum Beispiel eine Vergrößerung um das Anderthalbfache). öxä steht für die
- Gauß-Klammer, also den Wert von x mit abgehackten Nachkommastellen. Für
- Texteffekte gilt die folgende Formel, das Resultat sind wieder die benötigten
- Bytes:
-
- Breite
- 8 5
- Höhe * ( ------- + 2)
- 8 5
- 8
-
- Nur sind mit Höhe und Breite diesmal die Ausmaße des Zeichens nach der An~
- wendung der Effekte gemeint.
-
- Werden nur die Texteffekte oder nur die Größenänderung genutzt, so genügt
- es, scratchArea auf einen genügend großen Speicherbereich weisen zu lassen.
- Werden beide kombiniert angewandt, so muß der von scratchArea markierte
- Bereich die Summe beider Formeln an Bytes umfassen und in scratchOff2 die
- Anzahl der Bytes für die Größenänderung stehen (es dürfen nur gerade Werte
- verwendet werden).
- 5.6 Bibliothek: Die Line A-Routinen 5- 52
- ________________________________________________________
-
-
- textBg Hintergrundfarbe für die Textdarstellung
- copyTrans Zeigt an, daß die Routine CopyRasterForm transparent
- kopieren soll, sonst kopiert sie überdeckend
-
-
- Der Deskriptor für BitBlockTransfer
-
- Der Deskriptor enthält alle Parameter, die für die Ausführung eines BitBlock
- Transfer nötig sind. Die Definition hat den Bezeichner BBTDeskriptor und ent~
- hält folgende Verbund-Komponenten:
-
- Bezeichner Bedeutung
-
- w Breite des Quellbereichs in Pixeln
- h Höhe des Quellbereichs in Pixeln
- destPlanes Anzahl der Bitebenen (des Zielbereichs)
- setBitCol Farbe für im Quellbereich gesetzte Bits, allerdings nicht
- als Farbindex, sondern als Bitmuster, in dem jeweils ein
- Bit für eine Bitebene steht (Bit 0 entspricht erster Bit~
- ebene)
- unsetBitCol Farbe für im Quellbereich ungesetzte Bits. Format wie
- oben.
-
- Verknüpfungsart für Planes, bei denen das
- mode00 setBitCol-Bit und das unsetBitCol-Bit gleich Null ist
- mode01 setBitCol-Bit gleich Null und das unsetBitCol-Bit Eins ist
- mode10 setBitCol-Bit gleich Eins und das unsetBitCol-Bit Null ist
- mode11 setBitCol-Bit gleich Eins und das unsetBitCol-Bit Eins ist
-
- Die sechs letzten Variablen sind nur für transparente Kopiervorgänge relevant.
- Beim deckenden Kopieren wird setBitCol und unsetBitCol auf Null gesetzt und
- die zu benutzende Verknüpfungsart in mode00 eingetragen.
-
- Hinweis: Zu den Verknüpfungsarten siehe GrafBase.BitOperation.
-
- sourceStart Startpunkt des Quellbereichs in Pixeln
- sourceAddr Anfangsadresse des Quellbereichs (nicht des Quellrasters)
- sourceInc Schrittweite im Quellbereich in Byte (normalerweise:
- Anzahl der Bitebenen des Quellbereichs * 2)
- sourceWidth Breite einer Scan-Zeile des Quellrasters in Bytes
- sourceWidth2 Bei transparenter Kopie gleich Null, sonst gleich source~
- Width
- destStart Startpunkt des Zielbereichs in Pixeln
- destAddr Anfangsadresse des Zielbereichs (nicht des Zielrasters)
- destInc Schrittweite im Zielbereich in Byte
- (normalerweise: Anzahl der Bitebenen des Zielbereichs * 2)
- 5.6 Bibliothek: Die Line A-Routinen 5- 53
- ________________________________________________________
-
-
- destWidth Breite einer Scan-Zeile des Zielrasters in Bytes
- destWidth2 Bei transparenter Kopie gleich Null, sonst gleich dest~
- Width
- patternPtr Zeiger auf ein Füllmuster, das während des Kopiervor~
- gangs als Maske verwendt wird (Ist er NIL, so wird un~
- maskiert kopiert.)
- patternWidth Breite einer Zeile des Füllmusters in Byte (Der aktuelle
- Algorithmus scheint Probleme mit dieser Variable zu
- haben und nimmt evtl. immer eine Breite von 2 Byte an)
- patPlaneOff Null bedeutet, daß das Füllmuster nur eine Bitebene be~
- sitzt, sonst steht hier Zahl der Bytes für eine Bitebene.
- patternEnd Anzahl der Zeilen des Füllmusters (alle Bitebene zusam~
- men) multipliziert mit patternWidth
- scratch Bereich, der von der Kopierroutine als Variablenspeicher
- benutzt wird. Muß nicht initialisiert werden.
- 5.7 Bibliothek: GEM 5- 54
- ________________________________________________________
-
-
- 5.7 GEM
-
- GEM steht für Graphics Environment Manager und ist schlicht und ergreifend
- die auf dem Atari ST implementierte grafische Benutzeroberfläche. Dem
- Programmierer stellt sie ein umfangreiches Paket an Routinen zur Verfügung,
- das sowohl Dialog-, Fenster-, Menüverwaltung und ähnliches umfaßt als auch
- Prozeduren enthält, die eine einheitliche Schnittstelle zur Benutzung
- verschiedener Ein- und Ausgabegeräte bilden. Das GEM besteht aus zwei
- großen Bibliotheken, dem VDI und dem AES.
-
-
- VDI
-
- Das VDI (Virtual Device Interface) umfaßt allgemeine Ein- und Ausgabeopera~
- tionen, deren Benutzung von der aktuellen Implementierung der Routinen relativ
- unabhängig ist.
-
- Theoretisch kann man zwischen zwei verschiedenen Koordinatensystemen
- wählen. Im
-
- NDC (Normalisierte Gerätekoordinaten)-System liegt der Ursprung (0, 0) in der
- linken unteren, Ecke und die rechte obere Ecke besitzt die Koordinaten
- (32767, 32767). Dieses System hat den Vorteil einer allgemeinen Verwend~
- barkeit, es ist aber im aktuellen TOS nicht implementiert;
-
- RC (Raster Koordinaten)-System ist der Ursprung (0, 0) die linke, obere Ecke,
- und die Koordinaten der rechten unteren Ecke hängen von der Auflösung des
- Ausgabegerätes ab; sie betragen beispielsweise auf dem monochromen
- Bildschirm (639, 399).
-
- Bei jedem Aufruf einer VDI-Prozedur muß als erster Parameter eine Geräte~
- kennung (GEMEnv.DeviceHandle) übergeben werden. Diese Kennung teilt dem
- VDI mit, auf welchem Gerät die Ein- oder Ausgabe stattfinden soll. Meist ist
- dies die Kennung für eine virtuelle Bildschirmarbeitsstation (virtual screen
- workstation). Dies bewirkt eine ganz normale Ausgabe auf den Bildschirm. Wie
- erhält man nun solch eine Kennung? Dafür gibt es zwei Möglichkeiten. Erstens
- kann man die Routine GEMEnv.InitGem aufrufen und meldet sich dadurch
- sowohl beim VDI als auch beim AES an. Außerdem erhält man, falls die
- Anmeldung glückt, auch noch eine Kennung für eine virtuelle Bildschirm~
- arbeitsstation, mit deren Hilfe man nun auf den Bildschirm zugreifen kann. Die
- zweite Möglichkeit besteht in einem Aufruf von GEMEnv.OpenDevice. Diese
- Möglichkeit sollte aber erst für das zweite und folgende Geräte benutzt
- werden.
-
- Ist man mit allen Arbeiten auf dem Gerät fertig, so sollte dies mit GEMEnv.
- CloseDevice geschlossen werden. Eine Beschreibung der Funktionsweise und
- Parameter der einzelnen VDI-Prozeduren findet man im Anhang B.
- 5.7 Bibliothek: GEM 5- 55
- ________________________________________________________
-
-
- AES
-
- Das AES (Application Environment Services) unterstützt eine Anwendung, das
- heißt ein vom Benutzer gestartetes Programm, bei der Verwaltung von
- Fenstern, Dialogboxen, Menüs und ähnlichem. Außerdem ermöglicht es teilweise
- eine quasiparallele Abarbeitung mehrerer Prozesse. Dies sind einerseits bis zu
- sechs Desk-Accessories und andererseits die aktuelle Anwendung. Da die
- Datenstrukturen und Funktionen des AES zum Teil recht komplex sind, sollen
- sie im Folgenden einzeln betrachtet werden.
-
-
- Das Konzept der GEM-Resourcen
-
- Als Resource einer Anwendung bezeichnet man die Objekte, die zur Kommuni~
- kation mit der Außenwelt dienen. Dies können zum Beispiel Dialogboxen oder
- Menüzeilen sein. Die GEM-Resourcen befinden sich in der Regel in einem
- Resource-File, das durch den Suffix .RSC kenntlich gemacht wird. Erzeugt
- wird dieses File mit einem Resource Construction Set (Siehe auch Anhang
- C.2). Allerdings ist es auch möglich, die Resourcen zur Laufzeit von
- Programmen selber erstellen oder ändern zu lassen (siehe Modul ObjHandler).
-
-
- Verwaltung der GEM-Resourcen
-
- Liegt ein Resource-File vor, so sollte dies während der Initialisierung der An~
- wendung mit AESResources.LoadResource geladen werden. Mit Hilfe von
- AESResources.ResourceAddr und der Resource-Indizes können jetzt die Adressen
- der einzelnen Objektbäume und anderer Strukturen (siehe auch Abschnitt über
- Objektbäume) ermittelt werden. Die Resource-Indizes kennt eine Anwendung
- durch das Importieren des Definitonsmoduls, das vom Resource Construction
- Set beim Speichern der Resource erzeugt wird. Die Indizes sind in dem Modul
- als Konstanten deklariert. Die Bezeichner dieser Konstanten entsprechen de~
- nen, die während der Erstellung der einzelnen Objekte im Resource Construc~
- tion Set eingegeben wurden. Wenn eine Resource nicht mehr gebraucht wird,
- sollte ihr Speicherplatz durch AESResources.FreeResource freigegeben werden.
-
-
- Die Struktur des Objektbaumes
-
- Eine Resource besteht im wesentlichen aus Objektbäumen. Diese dienen sowohl
- zur Beschreibung von Dialogformularen und Menüzeilen, als auch zum Erstellen
- eigener Desktopoberflächen. Der Objektbaum und alle seine Elemente sind im
- Modul GEMGlobals definiert.
- 5.7 Bibliothek: GEM 5- 56
- ________________________________________________________
-
-
- ACHTUNG: Da die Typdefinitionen von Modula und C (Muttersprache des
- GEM) teilweise nicht kompatibel sind, sind die Objektdeklarationen
- oft sehr allgemein gehalten. Zum Beispiel ist Object.type als
- CARDINAL deklariert, obwohl weiter oben ein Typ ObjType
- definiert wurde, der ja eigentlich als Wertebereich für
- Object.type dienen soll. Der Grund dafür ist einfach, daß die
- Ordinalzahlen für die Objekttypen erst bei 20 anfangen, ein
- Modula-Aufzählungstyp aber bei Null beginnt. Das ist alles
- ungefährlich, solange ausschließlich die Routinen der GEM-
- Bibliotheksmodulen zum Verarbeiten der Objekte verwendet
- werden (Dort werden alle Typwandlungen und -transformationen
- automatisch durchgeführt). Sobald man aber direkt auf die
- Objektstruktur zugreifen will, sollte man sich vorher über die
- interne Darstellung von Variablen durch den Modula-Compiler
- und das GEM informieren.
-
- Der Baum ist ein Feld (Array) aus Objekten (Object) und wird mit Hilfe eines
- Zeigers (PtrObjTree) referenziert. Der Baumindex eines Objektes ist nichts
- weiter als nur der Feldindex innerhalb des Baumes. Ein Objekt ist ein Verbund,
- der aus einer allgemeinen Objektbeschreibung (Stellung im Baum, Größe etc.)
- und eventuell noch einem Zeiger auf eine typabhängige Objektspezifikation
- besteht. Dieser Verbund enthält folgende Elemente:
-
- Bezeichner Bedeutung
-
- next Index des rechten Nachbarobjektes, entspricht dem
- nächsten Objekt der Nachfolgerliste (Das rechteste Ob~
- jekt einer Nachfolgerliste enthält den Index Vorgängers)
- head Kopf (linkestes Objekt) der Nachfolgerliste des Objekts
- tail Ende (rechtestes Objekt) der Nachfolgerliste des Objektes
-
- Ist eine der drei vorausgegangenen Variablen gleich NoObject, so existiert das
- bezeichnete Objekt nicht. Das bedeutet für head und tail, daß das Objekt keine
- Nachfolgerliste und somit auch keine Nachfolger besitzt. Und für next, daß
- weder Nachbarn noch ein Vorgänger existieren, das heißt das Objekt ist die
- Wurzel des Baumes.
-
- type Gibt an, von welchem Typ das Objekt ist
- flags Gibt die Flags des Objektes an
- state Bestimmt den Objektstatus
- spec Enthält die typabhänige Objektbeschreibung
- space Gibt den vom Objekt belegten Rechteckbereich an. Dabei
- ist zu beachten, daß die Position relativ zum Vorgänger~
- objekt angegeben wird. Nur die Koordinaten des Wurzel~
- objektes sind absolute Bildschirmkoordinaten.
- 5.7 Bibliothek: GEM 5- 57
- ________________________________________________________
-
-
- Folgende Objekttypen werden unterstützt:
-
- Bezeichner Bedeutung
-
- boxObj Stellt ein gefülltes Rechteck dar. Die Objektspezifikation
- gibt Farbe und Randstärke an.
- textObj Steht für einen Schriftzug. Objektspezifikation ist ein
- Zeiger auf eine TEdInfo-Struktur.
- boxTextObj Stellt eine Kombination der beiden vorangegangenen Ob~
- jekttypen dar. Spezifikation wie bei textObj.
- imageObj
- Es wird ein Bitmuster dargestellt. Spezifikation ist ein
- Zeiger auf einen BitBlock-Verbund.
- progDefObj Selbstdefinierbares Objekt. Spezifikation ist ein Zeiger
- auf eine ApplBlock-Struktur. Näheres zu diesem Typ
- kann im Definitionsmodul von ObjHandler nachgelesen
- werden.
- iBoxObj Dies ist ein Rechteck, von dem nur der Rahmen sichtbar
- ist. Hat dieser die Stärke Null, so ist es unsichtbar.
- Objektspezifikation entspricht boxObj. Dieser Objekttyp
- wird meist zum Zusammenfassen von mehreren
- Unterobjekten benutzt.
- buttonObj Solche Objekte werden in der Regel als Knopf in Dialog~
- boxen benutzt. Es wird ein Text zentriert in einem weiß
- gefüllten Rechteck ausgegeben. Die Spezifikation ist ein
- Zeiger auf eine Zeichenkette.
- boxCharObj Entspricht boxObj, nur wird innerhalb des Rechteckes ein
- Zeichen zentriert dargestellt. In der Spezifikation befindet
- sich zusätzlich noch der ASCII-Wert des Zeichens.
- stringObj Stellt die Zeichenkette dar, auf die die Spezifikation
- zeigt. Wird für die Einträge in den Pull-Down-Menüs
- verwendet.
- fTextObj Entspricht textObj, doch ist der Text hier edierbar.
- fBoxTextObj Wie fTextObj, doch wird der Text innerhalb eines gefüll~
- ten Rechtecks dargestellt.
- iconObj Beschreibt ein Piktogramm (Icon). Dieses besteht aus ei~
- nem maskierten Bitmuster, einer Bildunterschrift und ei~
- nem Zeichen. Spezifikation ist ein Zeiger auf einen Icon~
- Block-Verbund.
- titleObj Entspricht stringObj, wird allerdings für die Menütitel
- verwendet.
- 5.7 Bibliothek: GEM 5- 58
- ________________________________________________________
-
-
- Es folgen die Objektflags:
-
- Bezeichner Bedeutung
-
- selectFlg Zeigt an, daß das Objekt bei einem Dialog durch einen
- Mausklick angewählt werden kann
- defaultFlg Besitzt ein Objekt dieses Flag, so wird es angewählt,
- wenn während eines Dialoges die <Return>-Taste betätigt
- wird. Das Flag sollte pro Dialogformular nur einmal
- vorkommen.
- selectExitFlg Bestimmt, daß der Dialog abgebrochen wird, sobald das
- so gekennzeichnete Objekt angewählt wird.
- editFlg Zeigt an, daß das Objekt einen edierbaren Text enthält.
- radioButFlg Kennzeichnet eine Gruppe von Objekten, von denen immer
- nur eines gleichzeitig angewählt sein kann. Wird ein
- zweites angeklickt, so wird das erste wieder deselektiert.
- Die Elemente der Gruppe müssen denselben Vorgänger
- besitzen.
- lastObjFlg Bestimmt das letzte Objekt eines Baumes, also das mit
- dem größten Objektindex.
- touchExitFlg Wird auf einem solchen Objekt während des Dialoges der
- Mausknopf gedrückt, so wird der Dialog beendet. Der
- Knopf muß im Gegensatz zu selectExitObj nicht wieder
- losgelassen werden.
- hideTreeFlg
- Das so gekennzeichnete Objekt und all seine Nachfolger
- werden von einem AESObjects.DrawObject oder
- AESObjects.FindObject ignoriert.
- indirectFlg Besagt, daß Object.spec nicht die wirkliche Objektbe~
- schreibung, sondern nur einen Zeiger auf sie enthält.
-
- Folgende Objektzustände sind möglich:
-
- Bezeichner Bedeutung
- selectObj Das Objekt wird invers dargestellt und gilt somit als an~
- gewählt
- crossObj Es wird ein Kreuz durch das Objekt gezeichnet
- checkObj Das Objekt wird mit einem Hacken versehen
- disableObj Das Objekt wird aufgehellt. Bezeichnet nicht anwählbare
- Objekte
- outlineObj Es wird ein Rahmen um das Objekt gezeichnet
- shadowObj Das Objekt erhält beim Zeichnen einen Schatten.
-
- Die Objektspezifikation enthält grundsätzlich eine von zwei Strukturen. Entwe~
- der ist sie ein Zeiger auf die eigentliche Beschreibung (zum Beispiel TEdInfo),
- oder sie enthält die Objektfarbe und die Randdicke des Objektes. Letzteres ist
- 5.7 Bibliothek: GEM 5- 59
- ________________________________________________________
-
-
- bei boxObj und iBoxObj der Fall, außerdem gilt es auch für boxCharObj, nur
- wird hier zusätzlich noch der ASCII-Wert des Zeichens angegeben. Die Rand~
- stärke kann Werte zwischen -128 und 127 annehmen, dabei wächst der Rand
- bei positiven Werten nach innen und bei negativen nach außen. Bei Objekten
- vom Typ boxObj, iBoxObj, box CharObj und bei Objekten, die einen Zeiger auf
- eine TEdInfo-Struktur als Spezifikation besitzen, besteht die Objektfarbe aus
- folgenden Komponenten: Randfarbe, Farbe für den Text, Schreibmodus für die
- Darstellung von Text (ist entweder deckend oder transparent), Füllmuster und
- Füllfarbe. Es existieren 8 verschiedenen Füllmuster, dabei stehen die Werte
- von 1 bis 6 für Punktmuster, die mit steigendem Wert immer dunkler werden.
- 0 bedeutet keine Füllung und 7 vollständiges Füllen mit der Füllfarbe.
-
- Jetzt fehlt nur noch die Beschreibung für die einzelnen Objektspezifikationen.
-
-
- Die TEdInfo-Struktur
-
- dient zur Beschreibung von edierbarem und nicht edierbarem Text. Ist der Text
- nicht edierbar, so werden tmpltPtr und validPtr nicht ausgewertet.
-
- Bezeichner Bedeutung
-
- textPtr Zeiger auf die Zeichenkette, die den aktuellen Text ent~
- hält
- tmpltPtr Zeiger auf die Zeichenkette, die die Textmaske enthält.
- Der aktuelle Text wird dort in die Maske eingesetzt, wo
- diese das ' '-Zeichen enthält. Die dadurch erzeugte Zei~
- _
- chenkette wird auf dem Bildschirm dargestellt
- validPtr Zeiger auf die Zeichenkette, die bestimmt, welche
- Zeichen eingegeben werden dürfen. Dabei stehen folgende
- Character für die jeweils beschriebene Zeichenmenge:
- 9 -- Erlaubt die Ziffern von 0 bis 9
- A -- Erlaubt alle Großbuchstaben von A bis Z und das
- Leerzeichen
- a -- Erlaubt Groß- und Kleinbuchstaben und das Leer-
- zeichen
- F -- Erlaubt Filenamen mit den Sonderzeichen "?", "*"
- und ":"
- P -- Erlaubt Pfadnamen mit "ü", "?", "*" und ":"
- p -- Erlaubt Pfadnamen mit "ü", ":"
- X -- Erlaubt alle Zeichen
- font Bestimmt den zu verwendenden Zeichensatz
- (StandardFont oder SmallFont)
- res1 Reserviert für zukünftige Anwendungen
- just Bestimmt die Textausrichtung
- color Bestimmt Farbe und ähnliches (siehe obige Beschreibung
- der Objektfarbe)
- 5.7 Bibliothek: GEM 5- 60
- ________________________________________________________
-
-
- res2 Reserviert für zukünftige Anwendungen
- thickness Randstärke
- textLen Maximallänge des aktuellen Textes (abschließende Null
- mitzählen)
- tmpltLen Länge der Textmaske (abschließende Null mitzählen)
-
-
- Die IconBlock-Struktur
-
- bestimmt das Aussehen von Piktogrammen. Das Aussehen des eigentlichen
- Bildchens wird durch zwei Bitmuster bestimmt, die Maske und die Daten. Dies
- dient dazu, daß der Hintergrund nicht durchscheinen kann und das Objekt auch
- im invertierten Zustand anständig aussieht. Die Maske wird normalerweise
- benutzt, um den Hintergrund dort zu löschen, wo er nicht erwünscht ist; die
- Daten bestimmen dann das eigentliche Aussehen des Icons.
-
- Bezeichner Bedeutung
-
- mask Zeiger auf das Bitmuster der Maske
- data Zeiger auf das Bitmuster der Daten
- text Zeiger auf die Zeichenkette der Bildunterschrift
- color Die 4 höchstwertigen Bits enthalten den Farbindex für die
- gesetzten Datenbits, den Schriftzug und das Zeichen. Die
- 4 niederwertigen Bits geben den Farbindex für die ge~
- setzten Maskenbits und den Texthintergrund an
- oneChar ASCII-Wert des im Icon dargestellten Zeichens, ist er
- gleich 0C, so wird nichts dargestellt
- charPos Position des Zeichens relativ zur Objektposition
- iconFrame Ausmaße des Bitmusters. Die Position ist relativ zu der
- des Objektes, außerdem sollte die Breite ein Vielfaches
- von 16 sein
- textFrame Ausmaße des Schriftzuges. Positionsangabe ist relativ
-
-
- Die BitBlock-Struktur
-
- beschreibt ein einfaches Bitmuster.
-
- Bezeichner Bedeutung
-
- data Zeiger auf das Bitmuster
- bytes Breite des Bitmusters in Byte, dieser Wert muß gerade
- sein
- h Höhe des Musters in Pixeln
- x Horizontaler Offset, der es erlaubt, jedes beliebige Bit an
- den linken Rand zu setzen
- y Vertikaler Offset
- 5.7 Bibliothek: GEM 5- 61
- ________________________________________________________
-
-
- color Farbindex für das Bitmuster
-
-
- Die ApplBlock-Struktur
-
- beschreibt ein selbstdefinierbares Objekt. Dies geschieht, indem eine Prozedur
- angegeben wird, die das Objekt wahlweise zeichnet oder seinen Status ändert.
- Der Prozedur kann ein 32 bit breiter Parameter übergeben werden, der das
- Aussehen des Objektes näher beschreibt. Will man solch ein Objekt ohne die
- Routinen des Moduls ObjHandler benutzen, so hat man darauf zu achten, daß
- zum Zeitpunkt des Aufrufs der Zeichenprozedur die Registerbelegung nicht
- mehr den Modulakonventionen entspricht.
-
- Bezeichner Bedeutung
-
- code Startadresse der Zeichenprozedur. Die Prozedur be~
- kommt beim Aufruf einen Zeiger auf einen ParmBlock-
- Verbund übergeben.
- parm Parameter für die Prozedur
-
-
- Das Konzept der AES-Menuleisten
-
- Die Menuleisten werden mit Hilfe eines Objektbaumes dargestellt und sollten
- mit dem Resource Construction Set erstellt werden. Die Routinen zum Benut~
- zen der Pull-Down-Menus finden sich in dem Modul AESMenus. Die wichtigste
- von ihnen ist MenuBar, mit ihr werden die Menus aktiviert und auch wieder
- ausgeschaltet. Ein aktives Menu kann vom Anwender mit der Maus bedient
- werden. Wird ein Menupunkt angewählt, so erhält man ein Nachrichtenereignis
- mit der Kennung AESEvents.menuSelected.
-
-
- Accessories
-
- Accessories werden mit Hilfe der Prozedur AESMenus.RegisterAcc beim AES
- angemeldet. Nach der Anmeldung erscheint der Titel des Accessory's in jedem
- Menu und kann damit vom Benutzer angewählt werden. Wird es selektiert, so
- wird ihm eine Nachricht mit der Kennung AESEvents.accOpen gesendet, dabei
- übergibt das AES zur Kontrolle die bei der Anmeldung erhaltene Accessory-
- Kennung.
- 5.7 Bibliothek: GEM 5- 62
- ________________________________________________________
-
-
- Das Konzept der AES-Fenster
-
- Fenster dienen zum Darstellen von Informationen, sie sind in ihrer Größe und
- Position frei veränderbar und dürfen sich auch überlappen (Alle Prozeduren zur
- Fensterbehandlung findet man in AESWindows). Welche Bedienungselemente
- (Schieber, Titelzeile etc.) ein Fenster besitzt, wird von dem Anwendungs~
- programm während der Anforderung einer Fensterkennung mit CreateWindow
- festgelegt. Erhält die Anwendung eine Kennung ungleich NoWindow, so war die
- Anforderung erfolgreich, und diese Kennung muß dann immer als erster
- Parameter bei allen Funktionen angegeben werden, die auf diesem Fenster
- arbeiten sollen. Wird ein Fenster nicht mehr benötigt, so sollte die
- Fensterkennung mit DeleteWindow freigegeben werden.
-
- Soll das Fenster nun auf dem Bildschirm dargestellt werden, so muß
- OpenWindow aufgerufen werden. Es ist nun sichtbar, und die Anwendung muß
- dafür sorgen, daß, sobald das AES eine entsprechende Nachricht schickt, der
- Fensterinhalt erneuert wird. Soll das Fenster wieder verschwinden, so wird
- dies dem AES mittels Close Window mitgeteilt. Mit OpenWindow kann es
- daraufhin jederzeit wieder sichtbar gemacht werden, und der Ablauf beginnt
- von Neuem. Wird ein Fenster geöffnet, in seiner Größe verändert oder ein
- darüberliegendes Fenster verschoben, so kann es passieren, daß plötzlich
- sichtbar werdende Fensterinhalte der Neuzeichnung (redraw) bedürfen. Eine
- solches Ereignis veranlaßt das AES, eine Nachricht zur Neuzeichnung
- AESEvents.windRedraw zu schicken. Wird diese von der Anwendung
- empfangen, so wird im Regelfall ein Aktualisieren des Fensters angekündigt und
- der Mauszeiger versteckt. Jetzt wird die Rechteckliste vom AES geholt und
- der angegebene Bereich neu gezeichnet. Schlußendlich wird der Mauszeiger
- wieder sichtbar gemacht und das Ende der Neuzeichnung gemeldet.
-
- Die folgende Prozedur soll dies verdeutlichen; sie geht davon aus, daß dev eine
- virtuelle Bildschirmarbeitsstation (siehe VDI) ist. Ihr wird die Fensterkennung
- (handle) und der neuzuzeichende Bereich (frame) übergeben.
- 5.7 Bibliothek: GEM 5- 63
- ________________________________________________________
-
-
- PROCEDURE RedrawFrame (handle:CARDINAL;
- frame:GrafBase.Rectangle);
-
- VAR clip : GrafBase.Rectangle;
-
- BEGIN
- (* Füllattribute für 'Bar' bestimmen *)
-
- VDIAttributes.SetFillType (dev, VDIAttributes.solidFill);
- VDIAttributes.SetFillColor (dev, GrafBase.white);
-
- (* Aktualisierung ankündigen und Mauszeiger aus *)
-
- UpdateWindow (TRUE);
- AESGraphics.GrafMouse (AESGraphics.mouseOff, NIL);
-
- (* 1. Element der Reckteckliste holen *)
-
- clip:=WindowRectList (handle, firstElem);
-
- WHILE clip.w # 0 DO (* 'w = 0' kennzeichnet Listenende *)
-
- (* Schnittbereich ermitteln und
- * Ausgabebereich beschränken
- *)
- clip:=GrafBase.ClipRect (frame, clip);
- VDIControls.SetClipping (dev, clip);
-
- VDIOutputs.Bar (dev, clip); (* Bereich mit Weiß füllen *)
-
- (* Hier können noch andere Sachen gezeichnet werden *)
-
- (* Nächstes Element der Rechteckliste holen *)
-
- clip:=WindowRectList (handle, nextElem);
-
- END;
-
- VDIControls.DisableClipping (dev); (* Clipping aus *)
-
- (* Mauszeiger ein und Aktualisierungsende melden *)
- AESGraphics.GrafMouse (AESGraphics.mouseOn, NIL);
- UpdateWindow (FALSE);
- END RedrawFrame;
- 5.7 Bibliothek: GEM 5- 64
- ________________________________________________________
-
-
- Die Funktion der anderen (Fenster betreffenden) Nachrichten kann im Definitions~
- modul AESEvents und im Abschnitt über Ereignisse nachgelesen werden.
-
- Neben den oben beschriebenen Fenstern existiert noch ein weiteres. Es ist das
- Desktop-Fenster, welches die Kennung DeskHandle besitzt. Neuzeichnungen des
- Desktops müssen nicht von der Anwendung durchgeführt werden, sie sind Auf~
- gabe des AES. Dies hat natürlich den Nachteil, daß das Aussehen des Desk~
- tops im wesentlichen immer gleich ist. Dieser Nachteil wurde dadurch ausge~
- schaltet, daß es möglich ist, einen beliebigen Objektbaum mit SetNewDesk als
- Desktopoberfläche zu benutzen.
-
- Bei allen Aufgaben, die von der Größe des Desktops abhängen, sollten eben
- diese Ausmaße durch einen Aufruf von WindowSize (DeskHandle, workSize)
- ermittelt werden. Es wird die Bildschirmgröße, abzüglich der Menuzeile, in
- Pixeln geliefert.
-
-
- Das Konzept der AES-Ereignisse
-
- Die Ereignisse stellen meist Aktionen des Anwenders dar und werden mit den
- Routinen des Moduls AESEvents überwacht. Es existiert die Möglichkeit, die
- Ereignisse entweder einzeln oder zusammen zu überwachen. Letzteres ge~
- schieht durch MultiEvent und wird meist benutzt. Dabei stehen die folgenden
- Ereignisse zur Auswahl:
-
- keyboard -- Das Tastatur-Ereignis tritt ein, sobald eine Taste gedrückt wird.
- Als Ergebnis wird sowohl der IBM-Scan-Code der Taste als auch deren
- ASCII-Äquivalent, falls vorhanden, geliefert (siehe GEMGlobals.GemChar).
-
- mouseButton -- Ein Mausknopf-Ereignis tritt auf, sobald eine vorher bestimmte
- Kombination der Maustasten gedrückt ist. Die Maske bestimmt, welche
- Mausköpfe berücksichtigt werden sollen (Ist sie die leere Menge, so tritt das
- Ereignis auf alle Fälle ein). Der Status bestimmt nun, welche Knöpfe der
- Maske gedrückt sein müssen, damit das Ereignis auftritt. Außerdem kann
- angegeben werden, auf bis zu wie viele solche sich schnell wiederholende
- Zustände gewartet werden soll (Anzahl der Mausklicks). Die minimale
- Wiederholgeschwindigkeit kann mit SetDClickSpeed eingestellt werden. Als
- Ergebnis liefert dieses Ereignis die Position der Maus, die zur Zeit gedrückten
- Maustasten und Sondertasten der Tastatur und außerdem, wie oft der Zustand
- der Maustasten eingetreten ist (Mausklicks).
-
- firstRect, secondRect -- Ein Maus-Ereignis tritt auf, sobald sich der Mauszei~
- ger innerhalb oder außerhalb eines bestimmten Rechteckbereichs befindet. Als
- Ergebnis erhält man die Position des Zeigers, die gedrückten Mausknöpfe und
- Sondertasten der Tastatur (Dies sind <Alternate>, <Control> und die beiden
- <Shift>-Tasten).
- 5.7 Bibliothek: GEM 5- 65
- ________________________________________________________
-
-
- timer -- Das Zeitgeber-Ereignis erfüllt zwei verschiedene Funktionen. Erstens
- kann die Anwendung es dazu nutzen, nach einer gewissen Zeitspanne eine
- Meldung zu erhalten, und zweitens können damit andere Prozesse Rechenzeit
- zugeteilt bekommen. Letzteres nutzt im aktuellen Betriebssystem aber nur
- Accessories etwas.
-
- message -- Nachrichten-Ereignisse dienen zur Kommunikation mit anderen
- Prozessen, in der Regel dem AES oder einem Accessory. Ein solches Ereignis
- füllt ein varianten Verbund vom Typ MessageBuffer, der im ersten Wort immer
- die Art der Nachricht, im zweiten die Applikationsnummer des Senders und im
- dritten die Anzahl der Bytes, die über die 16 Standardbytes hinausgehen, ent~
- hält.
-
- Der Bezeichner für die Applikations-Identifikationsnummer endet immer auf Id
- und der für die über 16 hinausgehenden Bytes auf Rmd (siehe MessageBuffer).
-
- Es existieren folgende Nachrichtentypen:
-
- unspecMessage -- Bezeichnet eine nicht vom AES, sondern von einer
- beliebigen anderen Anwendung kommende Nachricht. In uMsgData steht der
- Anfang der Nachricht, deren Format vom Sender abhängt. Möglicherweise
- folgen noch mehr als die 16 normalen Bytes, die dann mit AESMisc.ApplRead
- gelesen werden müssen.
-
- menuSelected -- Diese Nachricht wird gesendet, nachdem der Anwender einen
- Eintrag in einem Menu angewählt hat. In selTitle steht der Index des Titels, in
- dem sich der Menupunkt befindet, und in selItem steht der Index des Eintrags.
- Der Menutitel muß vom Programm mit AESMenus.NormalTitle wieder normal
- dargestellt werden.
-
- windRedraw -- Diese Nachricht besagt, daß ein Fensterausschnitt neu
- gezeichnet werden muß (siehe auch Abschnitt über Fenster). Dabei steht in
- rdrwHdl die Kennung des Fensters, welches aktualisiert werden soll, und in
- rdrwFrame der neu zu zeichnende Rechteckbereich.
-
- windTopped -- Eine Nachricht dieser Art zeigt an, daß ein Fenster vom
- Anwender angeklickt wurde und es deshalb noch oben gebracht werden soll.
- Dadurch wird es aktiv, das heißt, seine Randelemente werden dargestellt.
- topHdl enthält die Kennung des angewählten Fensters.
-
- windClosed -- Solch eine Nachricht wird gesendet, nachdem der Anwender auf
- die Schließbox (links oben) eines Fensters geklickt hat. Daraufhin sollte das
- Fenster mit der Kennung clsHdl geschlossen werden.
-
- windFulled -- Diese Nachricht besagt, daß die Vergrößerungsbox (rechts oben)
- des Fensters, mit der Kennung fullHdl, angeklickt wurde. Das Fenster sollte
- nun in seiner Maximalgröße dargestellt werden.
- 5.7 Bibliothek: GEM 5- 66
- ________________________________________________________
-
-
- windArrowed -- Es wird mitgeteilt, daß der Benutzer auf einen Scroll-Pfeil
- oder einen Schieber geklickt hat, und daß der Inhalt des entsprechende
- Fensters (arrwHdl) jetzt verschoben werden sollte, wie es arrwMode angibt.
-
- windHSlid -- Besagt, daß der Schieber des Fensters mit der Kennung hSldHdl
- in die von horPos spezifizierte Position gebracht wurde. Der Inhalt des
- Fensters sollte daraufhin entsprechend verändert werden. Die Positionsangabe
- erfolgt in Promille (siehe auch WSliderValue) und gilt für den horizontalen
- Schieber.
-
- windVSlid -- Entspricht windHSlid, allerdings ist die Angabe nun für den
- vertikalen Schieber gedacht. Die Kennung ist vSldHdl und vertPos ist die
- Position.
-
- windSized -- Diese Nachricht wird gesendet, nachdem der Benutzer die Größe
- eines Fensters verändert hat. In sizeHdl steht die Fensterkennung und in
- sizeFrame befinden sich die neuen Fensterausmaße. Zum Zeitpunkt dieser
- Nachricht hat das Fenster noch die alte Größe, die neue muß erst noch
- gesetzt werden.
-
- windMoved -- Zeigt an, daß das Fenster, welches die Kennung moveHdl
- besitzt, verschoben wurde. Die neue Position, die erst noch gesetzt werden
- muß, steht in moveFrame.
-
- windNewTop -- Solch eine Nachricht wird gesendet, nachdem das Fenster mit
- der Kennung nwTpHdl nach oben gebracht wurde.
-
- accOpen -- Diese Nachricht erhält ein Accessory, nachdem der ihm
- zugeordnete Menutitel angewählt wurde. Die Identifikationsnummer des
- Accessories wird in aOpnMId geliefert. aOpnVoid dient nur als Platzhalter.
-
- accClose -- Hiermit wird einem Accessory mitgeteilt, daß es vom Bildschirm
- verschwinden muß. Dieser Fall kann eintreten, falls die laufende Anwendung
- terminiert, der Bildschirm gelöscht wird oder die AES-Fensterbibliothek neu
- initialisiert wird.
-
-
- Mit Hilfe der AESMisc.ApplWrite-Routine kann einer Anwendung eine Nachricht
- übermittelt werden. Damit diese korrekt ankommt, muß die Applikationsnummer
- des Empfängers angegeben werden und dieser muß auf ein Nachrichtenereignis
- warten. Die Applikationsnummer einer Anwendung kann mit Hilfe von AESMisc.
- ApplFind ermittelt werden. Das erste Wort der Nachricht sollte den Wert
- unspecMessage besitzen, das zweite die Identifikationsnummer des Senders
- und das dritte die Länge der Nachricht minus 16 Byte, falls die Gesamt~
- nachricht länger als 16 Byte ist.
- 5.7 Bibliothek: GEM 5- 67
- ________________________________________________________
-
-
- MEGA-GEM oder 'Eine Modula-Anpassung des GEM'
-
- Die vorliegende GEM-Bibliothek ist nicht einfach eine Konvertierung der
- bekannten C-Vorlagen, sondern sie paßt GEM an Modula an und nicht
- umgekehrt. Dies hat den Nachteil, daß alte Programme nicht ganz so einfach
- zu übernehmen sind, bietet dafür aber die Vorteile,
-
- -- daß die Programme sehr viel übersichtlicher werden, da erstens die
- Namensgebung aussagekräftiger ist und zweitens sinnvolle Verbunde
- geschaffen wurden, so daß die Prozeduren weniger Parameter besitzen und
- zum Beispiel bei der Beschreibung eines Punktes nicht mehr die x- und die
- y-Komponente getrennt deklariert werden müssen, sondern eine einzige
- Variable vom Typ Point ausreicht;
-
- -- daß ein Programm, das während der Testphase abstürzt, ohne sich vorher
- beim GEM abzumelden, nicht gleich das gesamte System mit sich reißt,
- sondern die erforderlichen Abmeldungen automatisch von der Bibliothek
- ausgeführt werden;
-
- -- daß der Benutzer sich an die Programmierung selbstdefinierter Objekte
- oder Interruptvektoren wagen kann, ohne erst einmal die Innereien des
- Rechners und die Funktionsweise des Mikroprozessors zu studieren;
-
- -- daß Fehler im Programm frühzeitig vom Laufzeitsystem erkannt werden,
- weil eine Variable den Bereich eines Aufzählungstypen verlassen hat (was
- oft das Neubooten des Rechners erspart);
-
- -- daß die Programmierung einfach komfortabler geworden ist.
-
- Wie oben erwähnt, wird bei der Terminierung eines Programmes, egal ob diese
- gewollt oder ungewollt ist, dafür gesorgt, daß eventuell noch ausstehende
- Abmeldungen beim GEM durchgeführt werden. Dies beinhaltet zum Beispiel
- auch, noch aktive Fenster zu schließen und abzumelden oder den Mauszeiger
- wieder sichtbar zu machen. Dabei werden nur solche Aktionen aufgehoben, die
- unter der Modulkennung des terminierenden Moduls vorgenommen wurden. Da
- es aber Modulen gibt, bei denen diese automatische Abmeldung nicht
- gewünscht ist, zum Beispiel residente oder Systemmodulen, gibt es die
- Möglichkeit, sich mit GEMEnv.SysInitGem anzumelden und damit eine Kennung
- zu erhalten, die vor der Abmeldung geschützt ist. Die An- und Abmeldung
- geschieht in der Regel folgendermaßen:
- 5.7 Bibliothek: GEM 5- 68
- ________________________________________________________
-
-
- IMPORT GEMEnv;
- FROM GEMGlobals IMPORT RC;
-
- VAR dev : GEMEnv.DeviceHandle;
- gemHdl : GEMEnv.GemHandle;
- success : BOOLEAN;
-
- BEGIN
- (* Anmelden. Gleichzeitig erhält man in 'dev' die Geräte-
- * kennung für eine virtuelle Arbeitsstation.
- *)
-
- GEMEnv.InitGem (RC, dev, success);
- IF success THEN (* Falls Anmeldung erfolgreich war, dann ...*)
-
- (* Eigene GEM-Kennung ermitteln *)
-
- gemHdl:=GEMEnv.CurrGemHandle ();
- .
- . (* Hauptprogramm ausführen *)
- .
- GEMEnv.ExitGem (gemHdl); (* Abmelden *)
-
- ELSE
-
- (* User mitteilen,
- * daß Anmeldung beim GEM
- * nicht erfolgreich war.
- *)
-
- END;
- END ... .
-
-
- Der Aufruf von InitGem ersetzt die Einzelaufrufe zur Anmeldung beim AES
- (appl init) und das Öffnen einer "virtual workstion" (v opnvwk) beim VDI.
- _ _
- Wenn Sie aber keine VDI-Funktionen aufzurufen haben - das kommt
- beispielsweise oft bei Accessories vor - können Sie mit GemEnv.InitApplication
- nur die AES-Anmeldung durchführen. Mit GemEnv.OpenDevice können Sie dann
- immer noch nachträglich das Öffnen der des Bildschirms beim VDI nachholen.
- Mehr dazu im Definitionstext von GemEnv.
- 5.7 Bibliothek: GEM 5- 69
- ________________________________________________________
-
-
- Zur Fehlerbehandlung ist folgendes zu sagen. Tritt zum Beispiel ein Fehler auf,
- weil ein ARRAY OF CHAR übergeben wurde, das zu wenig Elemente enthält, so
- wird ein ganz normaler Laufzeitfehler ausgelöst, in diesem Fall ein 'String
- Overflow'. Tritt der Fehler aber innerhalb einer ROM-Routine des GEM auf, so
- meldet diese den Fehler in der Regel mit Hilfe eines INTEGER-Wertes. Dieser
- Wert wird nicht direkt an das aufrufende Modul weitergeleitet, sondern der
- Fehler muß von diesem durch den Aufruf von GEMEnv.GemError erkannt
- werden. Ist dies geschehen, so kann der eigentliche INTEGER-Wert mit
- GEMEnv.ErrorNumber ermittelt werden. Tritt ein Fehler auf, der nicht mit
- GemError abgefragt wird, so wird eine Fehlerroutine ausgeführt. Näheres dazu
- im Defintionsmodul GEMEnv (Anhang B).
-
- Die Aufteilung der einzelnen Routinen auf die Module entspricht der logischen
- Anordnung innerhalb des GEM. Lediglich die Routinen des "Application
- Manager", des "File Selector Manager", des "Scrap Manager" und des "Shell
- Manager" sind in AESMisc zusammengefaßt, da diese "Manager" sehr wenig
- Routinen enthalten. Außerdem befinden sich alle Initialisierungsroutinen in
- GEMEnv. Die Namen sind normalerweise an die orginal C-Namen angelehnt, so
- daß sich ein GEM-gewohnter Programmierer innerhalb kurzer Zeit zurecht~
- finden sollte.
-
-
- Eine Stufe über GEM
-
- Ein Grund für eine Benutzeroberfläche nach Art des GEM ist wohl, daß sich
- der Programmierer einer Anwendung nicht mehr mit den Details der Ein- und
- Ausgabe befassen muß. In diesem Bereich ist der Schuß beim GEM ein wenig
- nach hinten losgegangen. Der Programmautor muß zwar nicht unbedingt wissen
- wieviele Pixel zur Laufzeit auf dem Bildschirm vorhanden sind, doch ist er oft
- mit der Bedienung des GEM so beschäftigt, daß er für sein eigentliches
- Problem kaum noch Zeit hat.
-
- Um diesen Makel ein wenig zu beheben, gibt es sieben Module, die den
- Umgang mit GEM ein wenig erleichtern sollen. Als erstes soll der ObjHandler
- erwähnt werden. Dieses Modul ermöglicht es, die Objektbäume auf einer Ebene
- zu bearbeiten, auf der es nicht nötig ist, genau über die Abbildung der
- Struktur im Speicher informiert zu sein. Es genügt, die einzelnen Objektbaum~
- elemente und ihre Funktion zu kennen. Auch die Typwandlungen und
- -transformationen werden für die einzelnen Variablen selbständig durchgeführt
- (siehe auch Abschnitt über Objektbäume). Sozusagen als kleines Bonbon ist es
- mit dem ObjHandler auch sehr einfach, die Möglichkeit der selbstdefinierbaren
- GEM-Objekte zu nutzen.
-
- Das zweite Modul heißt EventHandler und nimmt dem Programmierer einen Teil
- der immer wiederkehrenden Tipparbeit bei der Ereignisverwaltung ab. Es
- werden für jedes Ereignis einfach Prozeduren angemeldet, deren Verwaltung
- vom EventHandler übernommen wird. Tritt nun ein Ereignis auf, so werden die
- 5.7 Bibliothek: GEM 5- 70
- ________________________________________________________
-
-
- zugehörigen Prozeduren mit den entsprechenden Parametern aufgerufen. Dabei
- gibt es auch die Möglichkeit, Prozeduren anzumelden, die den Ereignisstrom
- aller Module, die diese GEM-Bibliothek benutzen, überwachen und filtern können.
-
- Des weiteren gibt es das Modul TextWindows, das, wie der Name schon sagt,
- die Verwaltung von Textfenstern übernimmt. Ein solches Textfenster wird von
- dem Anwendungsprogramm wie ein ganz gewöhnlicher Textbildschirm
- behandelt, das heißt die Prozeduren entsprechen denen von Terminal. Alle
- Operationen, wie das Reagieren auf Mausoperationen des Anwenders und das
- Neuzeichnen des Fensterinhaltes werden von TextWindows automatisch
- durchgeführt. Als kleines Extra ist es damit möglich, einzelne Zeichen vom
- Benutzer mit Hilfe des Mauszeigers anwählen zu lassen. So kann man z.B.
- Textbereiche aus einem Fenster herausziehen lassen oder sie markieren.
-
- Ein weiteres Modul trägt den Namen EasyGEM0 und enthält eine Reihe von
- Routinen, die bei der GEM-Programmierung des öfteren gebraucht werden. Die
- Programmierung von Dialogboxen wird durch Routinen unterstützt, die eine Box
- darstellen, einzelne Objekte animieren und die Box zum Schluß wieder
- entfernen. Einfache Dialoge können sogar mit einem einzigen Prozeduraufruf
- abgehandelt werden. Außerdem gibt es Prozeduren, die die Objekte von
- Dialogboxen mit Startwerten vorbelegen und die Ergebnisse auslesen.
-
- EasyGEM1 stellt Funktionen zum Verwalten eines Clipboards und einen
- komfortablen Aufruf der Dateiauswahlbox (FileSelector) zur Verfügung.
-
- Das Modul WindowBase dient zum Verwalten von Fenstern beliebigen Inhalts.
- Das Verhalten und der Inhalt der Fenster wird durch eine Reihe von frei
- wählbaren Prozedurvariablen bestimmt. Die gesamte Fensterverwaltung ist
- dabei weitgehend automatisiert worden, so daß das Programmieren von
- Fenstern möglichst einfach und ohne zuviel Programmieraufwand geschehen
- kann. Dennoch wurde darauf geachtet, daß dem Anwender gegenüber den
- AES-Fenstern möglichst keine Gestaltungsmöglichkeiten verschlossen wurden.
- Auch die Systemmodule WindowLists und TextWindows bauen auf WindowBase
- auf.
-
- WindowLists verwaltet Listen in einem Fenster, dies nutzt die Modula-Shell
- zum Beispiel für ihre Directory-Fenster. Das Modul kann immer verwendet
- werden, wenn eine Liste gleichartiger Daten zeilenweise in einem Fenster
- dargestellt werden soll, dabei wird jedem Datum eine Zeile zugeordnet.
-
-
- Und ganz unten...
-
- Wollen Sie selbst AES- oder VDI-Funktionen aufrufen, entweder weil Sie
- selbst die Kontrolle haben wollen oder weil eine neue GEM-Funktion in unserer
- GEM-Bibliothek noch nicht zur Verfügung steht, benutzen Sie dazu das Modul
- GEMBase (s. DEMO-Ordner: AESDemo & VDIDemo).
-